tempo-cli 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. data/.gitignore +4 -0
  2. data/Gemfile +4 -0
  3. data/Gemfile.lock +56 -0
  4. data/README.md +326 -0
  5. data/Rakefile +65 -0
  6. data/bin/tempo +477 -0
  7. data/features/arrange.feature +43 -0
  8. data/features/checkout.feature +63 -0
  9. data/features/end.feature +65 -0
  10. data/features/project.feature +246 -0
  11. data/features/report.feature +62 -0
  12. data/features/start.feature +87 -0
  13. data/features/step_definitions/tempo_steps.rb +138 -0
  14. data/features/support/env.rb +26 -0
  15. data/features/tempo.feature +13 -0
  16. data/features/update.feature +69 -0
  17. data/lib/file_record/directory.rb +11 -0
  18. data/lib/file_record/directory_structure/tempo/README.txt +4 -0
  19. data/lib/file_record/directory_structure/tempo/tempo_projects.yaml +6 -0
  20. data/lib/file_record/record.rb +120 -0
  21. data/lib/tempo/controllers/arrange_controller.rb +52 -0
  22. data/lib/tempo/controllers/base.rb +117 -0
  23. data/lib/tempo/controllers/checkout_controller.rb +42 -0
  24. data/lib/tempo/controllers/end_controller.rb +42 -0
  25. data/lib/tempo/controllers/projects_controller.rb +107 -0
  26. data/lib/tempo/controllers/records_controller.rb +21 -0
  27. data/lib/tempo/controllers/report_controller.rb +55 -0
  28. data/lib/tempo/controllers/start_controller.rb +42 -0
  29. data/lib/tempo/controllers/update_controller.rb +78 -0
  30. data/lib/tempo/models/base.rb +176 -0
  31. data/lib/tempo/models/composite.rb +71 -0
  32. data/lib/tempo/models/log.rb +194 -0
  33. data/lib/tempo/models/project.rb +73 -0
  34. data/lib/tempo/models/time_record.rb +235 -0
  35. data/lib/tempo/version.rb +3 -0
  36. data/lib/tempo/views/arrange_view.rb +27 -0
  37. data/lib/tempo/views/base.rb +82 -0
  38. data/lib/tempo/views/formatters/base.rb +30 -0
  39. data/lib/tempo/views/formatters/screen.rb +86 -0
  40. data/lib/tempo/views/projects_view.rb +82 -0
  41. data/lib/tempo/views/report_view.rb +26 -0
  42. data/lib/tempo/views/reporter.rb +70 -0
  43. data/lib/tempo/views/time_record_view.rb +30 -0
  44. data/lib/tempo/views/view_records/base.rb +117 -0
  45. data/lib/tempo/views/view_records/composite.rb +40 -0
  46. data/lib/tempo/views/view_records/log.rb +28 -0
  47. data/lib/tempo/views/view_records/project.rb +32 -0
  48. data/lib/tempo/views/view_records/time_record.rb +48 -0
  49. data/lib/tempo.rb +26 -0
  50. data/lib/time_utilities.rb +30 -0
  51. data/tempo-cli.gemspec +26 -0
  52. data/test/lib/file_record/directory_test.rb +30 -0
  53. data/test/lib/file_record/record_test.rb +106 -0
  54. data/test/lib/tempo/controllers/base_controller_test.rb +60 -0
  55. data/test/lib/tempo/controllers/project_controller_test.rb +24 -0
  56. data/test/lib/tempo/models/base_test.rb +173 -0
  57. data/test/lib/tempo/models/composite_test.rb +76 -0
  58. data/test/lib/tempo/models/log_test.rb +171 -0
  59. data/test/lib/tempo/models/project_test.rb +105 -0
  60. data/test/lib/tempo/models/time_record_test.rb +212 -0
  61. data/test/lib/tempo/views/base_test.rb +31 -0
  62. data/test/lib/tempo/views/formatters/base_test.rb +13 -0
  63. data/test/lib/tempo/views/formatters/screen_test.rb +94 -0
  64. data/test/lib/tempo/views/reporter_test.rb +40 -0
  65. data/test/lib/tempo/views/view_records/base_test.rb +77 -0
  66. data/test/lib/tempo/views/view_records/composite_test.rb +57 -0
  67. data/test/lib/tempo/views/view_records/log_test.rb +28 -0
  68. data/test/lib/tempo/views/view_records/project_test.rb +0 -0
  69. data/test/lib/tempo/views/view_records/time_record_test.rb +0 -0
  70. data/test/support/factories.rb +177 -0
  71. data/test/support/helpers.rb +69 -0
  72. data/test/test_helper.rb +31 -0
  73. metadata +230 -0
@@ -0,0 +1,212 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+
5
+ before do
6
+ # See Rakefile for directory prep and cleanup
7
+ @dir = File.join( Dir.home,"tempo" )
8
+ Dir.mkdir(@dir, 0700) unless File.exists?(@dir)
9
+ end
10
+
11
+ after do
12
+ FileUtils.rm_r(@dir) if File.exists?(@dir)
13
+ end
14
+
15
+ describe "Model::TimeRecord" do
16
+
17
+ it "has project as an accessible attribute" do
18
+ time_record_factory
19
+ has_attr_accessor?( @record_1, :description ).must_equal true
20
+ end
21
+
22
+ it "defaults to the current project" do
23
+ project_factory
24
+ Tempo::Model::TimeRecord.clear_all
25
+ @record_1 = Tempo::Model::TimeRecord.new({ description: "day 1 pet the sheep",
26
+ start_time: Time.new(2014, 1, 1, 7 ) })
27
+ @record_1.project.must_equal Tempo::Model::Project.current.id
28
+ end
29
+
30
+ it "has an accessible description" do
31
+ time_record_factory
32
+ has_attr_accessor?( @record_1, :description ).must_equal true
33
+ end
34
+
35
+ it "has a readable end time" do
36
+ time_record_factory
37
+ has_attr_reader?( @record_1, :end_time ).must_equal true
38
+ end
39
+
40
+ it "has readable tags" do
41
+ time_record_factory
42
+ has_attr_read_only?( @record_1, :tags ).must_equal true
43
+ end
44
+
45
+ it "is taggable with an array of tags" do
46
+ time_record_factory
47
+ @record_2.tag(["fungi", "breakfast"])
48
+ @record_2.tags.must_equal(["breakfast", "fungi"])
49
+ end
50
+
51
+ it "is untaggable with an array of tags" do
52
+ time_record_factory
53
+ @record_3.untag( ["horticulture"] )
54
+ @record_3.tags.must_equal(["trees"])
55
+ end
56
+
57
+ it "has a current project getter" do
58
+ time_record_factory
59
+ Tempo::Model::TimeRecord.current.must_equal @record_6
60
+ @record_6.end_time.must_equal :running
61
+ end
62
+
63
+ it "closes current when adding an end time to current" do
64
+ time_record_factory
65
+ @record_6.end_time = Time.new(2014, 1, 2, 19, 00 )
66
+ Tempo::Model::TimeRecord.current.must_equal nil
67
+ end
68
+
69
+ it "has a running? method" do
70
+ time_record_factory
71
+ @record_1.running?.must_equal false
72
+ @record_6.running?.must_equal true
73
+ end
74
+
75
+ it "has a duration method returning seconds" do
76
+ time_record_factory
77
+ @record_1.duration.must_equal 1800
78
+ @record_6.duration.must_be_kind_of Integer
79
+ end
80
+
81
+ it "closes out the last current project on new" do
82
+ time_record_factory
83
+ @record_1.end_time.must_equal @record_2.start_time
84
+ @record_2.end_time.must_equal @record_3.start_time
85
+
86
+ @record_4.end_time.must_equal @record_5.start_time
87
+ @record_5.end_time.must_equal @record_6.start_time
88
+ end
89
+
90
+ it "closes projects on the start day" do
91
+ time_record_factory
92
+ @record_3.end_time.must_equal Time.new(2014,1,1,23,59)
93
+ end
94
+
95
+ it "closes out new projects if not the most recent" do
96
+ project_factory
97
+ Tempo::Model::TimeRecord.clear_all
98
+ @record_2 = Tempo::Model::TimeRecord.new({ project: @project_2, description: "day 1 drinking coffee, check on the mushrooms", start_time: Time.new(2014, 1, 1, 7, 30 ) })
99
+ @record_1 = Tempo::Model::TimeRecord.new({ project: @project_1, description: "day 1 pet the sheep", start_time: Time.new(2014, 1, 1, 7 ) })
100
+ Tempo::Model::TimeRecord.current.must_equal @record_2
101
+ @record_1.end_time.must_equal @record_2.start_time
102
+ end
103
+
104
+ it "closes out all projects when init with an end time" do
105
+ project_factory
106
+ Tempo::Model::TimeRecord.clear_all
107
+ @record_1 = Tempo::Model::TimeRecord.new({ project: @project_2, description: "day 1 drinking coffee, check on the mushrooms", start_time: Time.new(2014, 1, 1, 7, 30 ) })
108
+ @record_2 = Tempo::Model::TimeRecord.new({ project: @project_1, description: "day 1 pet the sheep", start_time: Time.new(2014, 1, 1, 8 ), end_time: Time.new(2014, 1, 1, 10 ) })
109
+ @record_1.end_time.must_equal @record_2.start_time
110
+ Tempo::Model::TimeRecord.current.must_equal nil
111
+ end
112
+
113
+ it "errors when start time inside existing record" do
114
+ time_record_factory
115
+ proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 12 ) }) }.must_raise ArgumentError
116
+ end
117
+
118
+ it "errors when start time same as existing record" do
119
+ time_record_factory
120
+ proc { Tempo::Model::TimeRecord.new({ start_time: @record_1.start_time }) }.must_raise ArgumentError
121
+ end
122
+
123
+ it "errors when end time is before start time" do
124
+ Tempo::Model::TimeRecord.clear_all
125
+ proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 12 ), end_time: Time.new(2014, 1, 1, 10 ) }) }.must_raise ArgumentError
126
+ end
127
+
128
+ it "accepts and end time equal to start time" do
129
+ Tempo::Model::TimeRecord.clear_all
130
+ record = Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 12 ), end_time: Time.new(2014, 1, 1, 12 ) })
131
+ record.end_time.must_equal record.start_time
132
+ end
133
+
134
+ it "end time can equal a previous start time" do
135
+ Tempo::Model::TimeRecord.clear_all
136
+ r1 = Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ), end_time: Time.new(2014, 1, 1, 12 ) })
137
+ r2 = Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 8 ), end_time: Time.new(2014, 1, 1, 10 ) })
138
+ r1.start_time.must_equal r2.end_time
139
+ end
140
+
141
+ it "errors when end time is on a different day" do
142
+ Tempo::Model::TimeRecord.clear_all
143
+ proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ), end_time: Time.new(2014, 1, 2, 12 ) }) }.must_raise ArgumentError
144
+ end
145
+
146
+ it "errors when end time in existing record" do
147
+ Tempo::Model::TimeRecord.clear_all
148
+ r1 = Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ), end_time: Time.new(2014, 1, 1, 12 ) })
149
+ proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 8 ), end_time: Time.new(2014, 1, 1, 11 ) }) }.must_raise ArgumentError
150
+ end
151
+
152
+ it "errors when record spans an existing record" do
153
+ Tempo::Model::TimeRecord.clear_all
154
+ r1 = Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ), end_time: Time.new(2014, 1, 1, 11 ) })
155
+ proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 8 ), end_time: Time.new(2014, 1, 1, 12 ) }) }.must_raise ArgumentError
156
+ end
157
+
158
+ it "errors when record spans a running record" do
159
+ Tempo::Model::TimeRecord.clear_all
160
+ r1 = Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ) })
161
+ proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 8 ), end_time: Time.new(2014, 1, 1, 12 ) }) }.must_raise ArgumentError
162
+ end
163
+
164
+ it "has a valid start time check for existing record" do
165
+ time_record_factory
166
+ @record_2.valid_start_time?(@record_2.start_time).must_equal true
167
+ @record_2.valid_start_time?(@record_1.start_time).must_equal false
168
+ end
169
+
170
+ it "has a valid end time check for existing record" do
171
+ time_record_factory
172
+ @record_2.valid_end_time?(@record_2.end_time).must_equal true
173
+ @record_2.valid_end_time?(@record_3.end_time).must_equal false
174
+ end
175
+
176
+ it "comes with freeze dry for free" do
177
+ Tempo::Model::TimeRecord.clear_all
178
+ time_record_factory
179
+ @record_3.freeze_dry.must_equal({ :start_time=>Time.new(2014,1,1,17,30), :id=>3, :project=>3,
180
+ :end_time=>Time.new(2014,1,1,23,59), :description=>"day 1 water the bonsai",
181
+ :tags=>["horticulture", "trees"], :project_title=>"horticulture - backyard bonsai"})
182
+ end
183
+
184
+ it "saves to file a collection of projects" do
185
+ time_record_factory
186
+ Tempo::Model::TimeRecord.save_to_file
187
+ test_file_1 = File.join(ENV['HOME'],'tempo/tempo_time_records/20140101.yaml')
188
+ test_file_2 = File.join(ENV['HOME'],'tempo/tempo_time_records/20140102.yaml')
189
+ contents = eval_file_as_array( test_file_1 )
190
+ contents.must_equal [ "---", ":project_title: sheep herding", ":description: day 1 pet the sheep",
191
+ ":start_time: 2014-01-01 07:00:00.000000000 -05:00", ":end_time: 2014-01-01 07:30:00.000000000 -05:00",
192
+ ":id: 1", ":project: 1", ":tags: []",
193
+ "---", ":project_title: horticulture - basement mushrooms", ":description: day 1 drinking coffee, check on the mushrooms",
194
+ ":start_time: 2014-01-01 07:30:00.000000000 -05:00", ":end_time: 2014-01-01 17:30:00.000000000 -05:00",
195
+ ":id: 2", ":project: 2", ":tags: []",
196
+ "---", ":project_title: horticulture - backyard bonsai", ":description: day 1 water the bonsai",
197
+ ":start_time: 2014-01-01 17:30:00.000000000 -05:00", ":end_time: 2014-01-01 23:59:00.000000000 -05:00",
198
+ ":id: 3", ":project: 3", ":tags:", "- horticulture", "- trees"]
199
+ contents = eval_file_as_array( test_file_2 )
200
+ # TODO: test this one too when stable
201
+ contents.must_equal ["---", ":project_title: sheep herding", ":description: day 2 pet the sheep",
202
+ ":start_time: 2014-01-02 07:15:00.000000000 -05:00", ":end_time: 2014-01-02 07:45:00.000000000 -05:00",
203
+ ":id: 1", ":project: 1", ":tags: []",
204
+ "---", ":project_title: horticulture - basement mushrooms", ":description: day 2 drinking coffee, check on the mushrooms",
205
+ ":start_time: 2014-01-02 07:45:00.000000000 -05:00", ":end_time: 2014-01-02 17:00:00.000000000 -05:00",
206
+ ":id: 2", ":project: 2", ":tags: []",
207
+ "---", ":project_title: horticulture - backyard bonsai", ":description: day 2 water the bonsai",
208
+ ":start_time: 2014-01-02 17:00:00.000000000 -05:00", ":end_time: :running",
209
+ ":id: 3", ":project: 3", ":tags: []"]
210
+ end
211
+ end
212
+ end
@@ -0,0 +1,31 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+ describe "Views" do
5
+
6
+ before do
7
+ project_factory
8
+ Tempo::Views::Reporter.clear_records
9
+ end
10
+
11
+ describe "project list view" do
12
+
13
+ it "adds projects to reporter by default" do
14
+ Tempo::Views::projects_list_view
15
+
16
+ view = []
17
+ Tempo::Views::Reporter.view_records.each {|r| view << r.title}
18
+ view.must_equal [ "gardening", "horticulture - backyard bonsai", "horticulture - basement mushrooms", "sheep herding" ]
19
+ end
20
+
21
+ it "should be able to return a subset of projects" do
22
+ subset = Tempo::Model::Project.index[1..3]
23
+ Tempo::Views::projects_list_view subset
24
+
25
+ view = []
26
+ Tempo::Views::Reporter.view_records.each {|r| view << r.title}
27
+ view.must_equal [ "gardening", "horticulture - backyard bonsai", "horticulture - basement mushrooms" ]
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,13 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+ describe "Views" do
5
+ describe "Formatters" do
6
+
7
+ describe "Base" do
8
+ # Base formatter is an abstract class. See child classes for
9
+ # testing the format_records method
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,94 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+ describe "Views" do
5
+ describe "Formatters" do
6
+ describe "Screen" do
7
+
8
+ before do
9
+ view_records_factory
10
+ @formatter = Tempo::Views::Formatters::Screen.new
11
+ end
12
+
13
+ describe "Message View Records" do
14
+
15
+ it "outputs the message" do
16
+ records = [@message_1, @message_2]
17
+ out = capture_stdout { @formatter.format_records records }
18
+
19
+ assert_equal "All The Things I Did\non a busy busy day\n", out.string
20
+ end
21
+
22
+ it "raises an error when type error" do
23
+ proc { @formatter.format_records [@error] }.must_raise RuntimeError
24
+ end
25
+ end
26
+
27
+ describe "Duration View Records" do
28
+
29
+ it "outputs the duration" do
30
+ records = [@duration]
31
+ out = capture_stdout { @formatter.format_records records }
32
+
33
+ assert_equal "2:40\n", out.string
34
+ end
35
+ end
36
+
37
+ describe "Project View Records" do
38
+
39
+ it "outputs the project title" do
40
+ records = [@project_1]
41
+ out = capture_stdout { @formatter.format_records records }
42
+
43
+ assert_equal "sheep herding\n", out.string
44
+ end
45
+
46
+ it "accepts option to include tags with spacing" do
47
+ records = [@project_1, @project_2]
48
+ out = capture_stdout { @formatter.format_records records, { tags: true }}
49
+
50
+ assert_equal "sheep herding tags: none\n" +
51
+ "horticulture - basement mushrooms tags: [farming, fungi]\n", out.string
52
+ end
53
+
54
+ it "accepts option to include id" do
55
+ records = [@project_2]
56
+ out = capture_stdout { @formatter.format_records records, { id: true }}
57
+
58
+ assert_equal " [2] horticulture - basement mushrooms\n", out.string
59
+ end
60
+
61
+ it "accepts option to indent projects to proper depth" do
62
+ @project_1.depth = 3
63
+ records = [@project_1]
64
+ out = capture_stdout { @formatter.format_records records, { depth: true }}
65
+
66
+ assert_equal " sheep herding\n", out.string
67
+ end
68
+
69
+ it "indicates active project" do
70
+ records = [@project_1, @project_2]
71
+ out = capture_stdout { @formatter.format_records records, {active: true}}
72
+ assert_equal " sheep herding\n* horticulture - basement mushrooms\n", out.string
73
+ end
74
+ end
75
+
76
+ describe "TimeRecord View Records" do
77
+ it "has start/end time, duration, project and description" do
78
+ records = [@time_record_1]
79
+ out = capture_stdout { @formatter.format_records records }
80
+
81
+ assert_equal "07:00 - 07:30 [0:30] sheep herding: day 1 pet the sheep\n", out.string
82
+ end
83
+
84
+ it "outputs a running indicator" do
85
+ records = [@time_record_6]
86
+ out = capture_stdout { @formatter.format_records records }
87
+
88
+ assert_match /17:00 - \d{2}:\d{2}\*/, out.string
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,40 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+ describe "Views" do
5
+ describe "Reporter" do
6
+ it "adds and reports formats" do
7
+ Tempo::Views::Reporter.add_format :html, :json, :logs
8
+ Tempo::Views::Reporter.formats.must_equal [:html, :json, :logs]
9
+ end
10
+
11
+ it "collects view records as they are initialized" do
12
+ Tempo::Views::Reporter.clear_records
13
+ record_1 = Tempo::Views::ViewRecords::Message.new "a message to report"
14
+ record_2 = Tempo::Views::ViewRecords::Message.new "a second message to report"
15
+ record_3 = Tempo::Views::ViewRecords::Message.new "a third message to report"
16
+
17
+ Tempo::Views::Reporter.view_records.length.must_equal 3
18
+ end
19
+
20
+ it "raises and error when view records of unknown format" do
21
+ record = "an invalid record object"
22
+ proc { Tempo::Views::Reporter.add_view_record record }.must_raise Tempo::Views::InvalidViewRecordError
23
+ end
24
+
25
+ it "sends the reports to the screen formatter on report" do
26
+ Tempo::Views::Reporter.clear_records
27
+ record_1 = Tempo::Views::ViewRecords::Message.new "a message to report"
28
+
29
+ out = capture_stdout { Tempo::Views::Reporter.report }
30
+ assert_equal "a message to report\n", out.string
31
+ end
32
+
33
+ it "has a mutable collection of options" do
34
+ assert_equal Tempo::Views::Reporter.options, {}
35
+ Tempo::Views::Reporter.add_options({ tags: true, depth: 3, color: "red" })
36
+ assert_equal Tempo::Views::Reporter.options, { :tags=>true, :depth=>3, :color=>"red" }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,77 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+ describe "Views" do
5
+ describe "ViewRecords" do
6
+
7
+ describe "Message" do
8
+
9
+ it "has a type, category,and message attribute" do
10
+ record = Tempo::Views::ViewRecords::Message.new "a message view record"
11
+ record.type.must_equal "message"
12
+ record.category.must_equal :info
13
+ record.message.must_equal "a message view record"
14
+
15
+ record = Tempo::Views::ViewRecords::Message.new "an error message", category: :error
16
+ record.category.must_equal :error
17
+ end
18
+
19
+ it "has a default format" do
20
+ record = Tempo::Views::ViewRecords::Message.new "a message view record"
21
+ record.format.must_equal "a message view record"
22
+ end
23
+
24
+ it "adds itself to the Reporter" do
25
+ length_before = Tempo::Views::Reporter.view_records.length
26
+ record = Tempo::Views::ViewRecords::Message.new "a message view record"
27
+ Tempo::Views::Reporter.view_records.length.must_equal length_before + 1
28
+ end
29
+ end
30
+
31
+ describe "Duration" do
32
+
33
+ it "has a type of duration" do
34
+ record = Tempo::Views::ViewRecords::Duration.new
35
+ record.type.must_equal "duration"
36
+ end
37
+
38
+ it "starts with given seconds or default to zero" do
39
+ record = Tempo::Views::ViewRecords::Duration.new
40
+ record.total.must_equal 0
41
+
42
+ record = Tempo::Views::ViewRecords::Duration.new 30
43
+ record.total.must_equal 30
44
+ end
45
+
46
+ it "has add and subtract methods" do
47
+ record = Tempo::Views::ViewRecords::Duration.new 30
48
+ record.add 160
49
+ record.total.must_equal 190
50
+ record.subtract 50
51
+ record.total.must_equal 140
52
+ end
53
+
54
+ it "has a default format" do
55
+
56
+ record = Tempo::Views::ViewRecords::Duration.new 1800
57
+ record.format.must_equal "0:30"
58
+
59
+ record = Tempo::Views::ViewRecords::Duration.new 18000
60
+ record.format.must_equal "5:00"
61
+
62
+ record = Tempo::Views::ViewRecords::Duration.new 36300
63
+ record.format.must_equal "10:05"
64
+
65
+ record = Tempo::Views::ViewRecords::Duration.new 39000
66
+ record.format.must_equal "10:50"
67
+ end
68
+
69
+ it "accepts a formatting block" do
70
+ record = Tempo::Views::ViewRecords::Duration.new 39000
71
+ formatted = record.format {|d| "I have a duration of #{d.total} seconds!"}
72
+ formatted.must_equal "I have a duration of 39000 seconds!"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,57 @@
1
+ require "test_helper"
2
+
3
+ #TODO Useful tree traversal methods should become view helpers?
4
+ def parse_tree_to_composite_record records, options={}
5
+ depth = options.fetch( :depth, 0 )
6
+ parent = options.fetch( :parent, :root )
7
+ view = []
8
+
9
+ records.each do |r|
10
+ if r.parent == parent
11
+ v = Tempo::Views::ViewRecords::Composite.new r, depth: depth
12
+ view << v
13
+ if not r.children.empty?
14
+ child_opts = options.clone
15
+ child_opts[:depth] = depth + 1
16
+ child_opts[:parent] = r.id
17
+ child_array = parse_tree_to_composite_record records, child_opts
18
+ view.push *child_array
19
+ end
20
+ end
21
+ end
22
+
23
+ view
24
+ end
25
+
26
+ describe Tempo do
27
+ describe "Views" do
28
+ describe "ViewRecords" do
29
+ describe "Composite" do
30
+ before do
31
+ tree_factory
32
+ @record = parse_tree_to_composite_record Tempo::Model::Tree.index
33
+ end
34
+
35
+ it "has a depth attribute" do
36
+ inspector = ""
37
+ @record.each {|r| inspector += "<#{r.id}:#{r.depth}>"}
38
+ inspector.must_equal "<1:0><3:1><7:2><8:2><2:0><4:1><5:1><6:2>"
39
+ end
40
+
41
+ it "has a default format" do
42
+ @record[7].format.must_equal " Tree 6"
43
+ end
44
+
45
+ it "has a class max depth" do
46
+ Tempo::Views::ViewRecords::Composite.max_depth.must_equal 2
47
+ end
48
+
49
+ it "adds itself to the Reporter" do
50
+ length_before = Tempo::Views::Reporter.view_records.length
51
+ record = Tempo::Views::ViewRecords::Message.new "a message view record"
52
+ Tempo::Views::Reporter.view_records.length.must_equal length_before + 1
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,28 @@
1
+ require "test_helper"
2
+
3
+ describe Tempo do
4
+ describe "Views" do
5
+ describe "ViewRecords" do
6
+ describe "Log" do
7
+ before do
8
+ log_factory
9
+ @record = Tempo::Views::ViewRecords::Log.new @log_1
10
+ end
11
+
12
+ it "has a start_time and date id attribute" do
13
+ @record.d_id.must_equal "20140101"
14
+ @record.start_time.must_equal Time.new(2014, 1, 1, 7 )
15
+ end
16
+
17
+ it "has a default format" do
18
+ @record.format.must_equal "Messagelog 20140101-1 07:00"
19
+ end
20
+
21
+ it "accepts a formatting block" do
22
+ f = @record.format {|m| "#{m.d_id}-#{m.id}"}
23
+ f.must_equal "20140101-1"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
File without changes