tempo-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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