freshtrack 0.2.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.
- data/History.txt +4 -0
- data/License.txt +20 -0
- data/Manifest.txt +37 -0
- data/README.txt +30 -0
- data/Rakefile +4 -0
- data/bin/freshtrack +23 -0
- data/config/hoe.rb +74 -0
- data/config/requirements.rb +17 -0
- data/lib/freshbooks/extensions/base_object.rb +31 -0
- data/lib/freshbooks/extensions/project.rb +58 -0
- data/lib/freshbooks/extensions/task.rb +50 -0
- data/lib/freshbooks/extensions/time_entry.rb +53 -0
- data/lib/freshbooks/extensions.rb +5 -0
- data/lib/freshtrack/core_ext/array.rb +11 -0
- data/lib/freshtrack/core_ext/numeric.rb +5 -0
- data/lib/freshtrack/core_ext/time.rb +3 -0
- data/lib/freshtrack/core_ext.rb +3 -0
- data/lib/freshtrack/version.rb +9 -0
- data/lib/freshtrack.rb +107 -0
- data/log/debug.log +0 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/setup.rb +1585 -0
- data/spec/array_spec.rb +35 -0
- data/spec/base_object_spec.rb +51 -0
- data/spec/freshtrack_spec.rb +566 -0
- data/spec/numeric_spec.rb +21 -0
- data/spec/project_spec.rb +400 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/task_spec.rb +350 -0
- data/spec/time_entry_spec.rb +351 -0
- data/spec/time_spec.rb +37 -0
- data/tasks/deployment.rake +34 -0
- data/tasks/environment.rake +7 -0
- data/tasks/rspec.rake +21 -0
- data/tasks/website.rake +9 -0
- metadata +110 -0
data/spec/array_spec.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Array do
|
4
|
+
it 'should be groupable' do
|
5
|
+
Array.new.should respond_to(:group_by)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe 'when grouping' do
|
9
|
+
before :each do
|
10
|
+
@array = (1..10).to_a
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should require a block' do
|
14
|
+
lambda { @array.group_by }.should raise_error(ArgumentError)
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should accept a block' do
|
18
|
+
lambda { @array.group_by {} }.should_not raise_error(ArgumentError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return a hash' do
|
22
|
+
@array.group_by {}.should be_kind_of(Hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should group the elements by the return value of the block' do
|
26
|
+
[1,2,3,4,5,6,7,8,9,10]
|
27
|
+
expected = {
|
28
|
+
0 => [3,6,9],
|
29
|
+
1 => [1,4,7,10],
|
30
|
+
2 => [2,5,8]
|
31
|
+
}
|
32
|
+
@array.group_by { |x| x % 3 }.should == expected
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
Thing = FreshBooks::BaseObject.new(:attr)
|
4
|
+
ThingDeal = FreshBooks::BaseObject.new(:attr)
|
5
|
+
|
6
|
+
describe FreshBooks::BaseObject do
|
7
|
+
it 'should have a mapping function for Date' do
|
8
|
+
FreshBooks::BaseObject::MAPPING_FNS[Date].should respond_to(:call)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'Date mapping function' do
|
12
|
+
before :each do
|
13
|
+
@func = FreshBooks::BaseObject::MAPPING_FNS[Date]
|
14
|
+
@date = stub('date arg', :text => '2008-01-29')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should return a date' do
|
18
|
+
@func.call(@date).should be_kind_of(Date)
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return a date matching the text of its argument' do
|
22
|
+
@func.call(@date).to_s.should == @date.text
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe 'converting an instance to XML' do
|
27
|
+
before :each do
|
28
|
+
@thing = Thing.new
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should use the elem name' do
|
32
|
+
@thing.expects(:elem_name)
|
33
|
+
@thing.to_xml
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'getting the elem name' do
|
38
|
+
before :each do
|
39
|
+
@thing = Thing.new
|
40
|
+
@thing_deal = ThingDeal.new
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should be the class name, downcased' do
|
44
|
+
@thing.elem_name.should == 'thing'
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'should be underscored if the class name has CamelCase' do
|
48
|
+
@thing_deal.elem_name.should == 'thing_deal'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,566 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Freshtrack do
|
4
|
+
describe 'loading configuration' do
|
5
|
+
before :each do
|
6
|
+
File.stubs(:read).returns('')
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should load the contents of the .freshtrack.yml file' do
|
10
|
+
File.stubs(:expand_path).with('~/.freshtrack.yml').returns('~/.freshtrack.yml')
|
11
|
+
File.expects(:read).with('~/.freshtrack.yml').returns('')
|
12
|
+
Freshtrack.load_config
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should turn the file contents into data' do
|
16
|
+
file_contents = stub('lorem ipsum')
|
17
|
+
File.stubs(:read).returns(file_contents)
|
18
|
+
YAML.expects(:load).with(file_contents)
|
19
|
+
Freshtrack.load_config
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should store the configuration data' do
|
23
|
+
config = stub('config data')
|
24
|
+
YAML.stubs(:load).returns(config)
|
25
|
+
Freshtrack.load_config
|
26
|
+
Freshtrack.config.should == config
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'getting configuration data' do
|
31
|
+
before :each do
|
32
|
+
@config = {}
|
33
|
+
Freshtrack.stubs(:config).returns(@config)
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should provide easy access to the company name' do
|
37
|
+
@config['company'] = company = stub('company name')
|
38
|
+
Freshtrack.company.should == company
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should provide easy access to the token' do
|
42
|
+
@config['token'] = token = stub('token')
|
43
|
+
Freshtrack.token.should == token
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should provide easy access to the project/task mapping' do
|
47
|
+
@config['project_task_mapping'] = project_task_mapping = stub('project/task mapping')
|
48
|
+
Freshtrack.project_task_mapping.should == project_task_mapping
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'initialization' do
|
53
|
+
before :each do
|
54
|
+
@company = 'zee_company_boss'
|
55
|
+
@token = 'token goes here'
|
56
|
+
Freshtrack.stubs(:load_config)
|
57
|
+
Freshtrack.stubs(:config).returns({ 'company' => @company, 'token' => @token })
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should load the configuration' do
|
61
|
+
Freshtrack.expects(:load_config)
|
62
|
+
Freshtrack.init
|
63
|
+
end
|
64
|
+
|
65
|
+
it 'should use the config data to set up FreshBooks' do
|
66
|
+
FreshBooks.expects(:setup).with("#{@company}.freshbooks.com", @token)
|
67
|
+
Freshtrack.init
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe 'getting project data' do
|
72
|
+
before :each do
|
73
|
+
@project_name = :proj
|
74
|
+
@project_task_mapping = { @project_name => { :project => 'fb proj', :task => 'fb task' } }
|
75
|
+
Freshtrack.stubs(:project_task_mapping).returns(@project_task_mapping)
|
76
|
+
@project = stub('project')
|
77
|
+
@task = stub('task')
|
78
|
+
FreshBooks::Project.stubs(:find_by_name).returns(@project)
|
79
|
+
FreshBooks::Task.stubs(:find_by_name).returns(@task)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should require an argument' do
|
83
|
+
lambda { Freshtrack.get_project_data }.should raise_error(ArgumentError)
|
84
|
+
end
|
85
|
+
it 'should accept an argument' do
|
86
|
+
lambda { Freshtrack.get_project_data(@project_name) }.should_not raise_error(ArgumentError)
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should require the argument to be a valid project identifier' do
|
90
|
+
@project_task_mapping.delete(@project_name)
|
91
|
+
lambda { Freshtrack.get_project_data(@project_name) }.should raise_error
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'should accept an argument that is a valid project identifier' do
|
95
|
+
lambda { Freshtrack.get_project_data(@project_name) }.should_not raise_error
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should get the indicated FreshBooks project' do
|
99
|
+
FreshBooks::Project.expects(:find_by_name).with(@project_task_mapping[@project_name][:project]).returns(@project)
|
100
|
+
Freshtrack.get_project_data(@project_name)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should abort if no FreshBooks project found' do
|
104
|
+
FreshBooks::Project.stubs(:find_by_name).returns(nil)
|
105
|
+
lambda { Freshtrack.get_project_data(@project_name) }.should raise_error
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should provide easy access to the project' do
|
109
|
+
FreshBooks::Project.stubs(:find_by_name).returns(@project)
|
110
|
+
Freshtrack.get_project_data(@project_name)
|
111
|
+
Freshtrack.project.should == @project
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'should get the indicated FreshBooks task' do
|
115
|
+
FreshBooks::Task.expects(:find_by_name).with(@project_task_mapping[@project_name][:task]).returns(@task)
|
116
|
+
Freshtrack.get_project_data(@project_name)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should abort if no FreshBooks task found' do
|
120
|
+
FreshBooks::Task.stubs(:find_by_name).returns(nil)
|
121
|
+
lambda { Freshtrack.get_project_data(@project_name) }.should raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
it 'should provide easy access to the task' do
|
125
|
+
FreshBooks::Task.stubs(:find_by_name).returns(@task)
|
126
|
+
Freshtrack.get_project_data(@project_name)
|
127
|
+
Freshtrack.task.should == @task
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe 'getting time data' do
|
132
|
+
before :each do
|
133
|
+
@project_name = :proj
|
134
|
+
@time_data = stub('time data')
|
135
|
+
IO.stubs(:read).returns(@time_data)
|
136
|
+
Freshtrack.stubs(:convert_time_data)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'should require an argument' do
|
140
|
+
lambda { Freshtrack.get_time_data }.should raise_error(ArgumentError)
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'should accept an argument' do
|
144
|
+
lambda { Freshtrack.get_time_data(@project_name) }.should_not raise_error(ArgumentError)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should accept an option string' do
|
148
|
+
lambda { Freshtrack.get_time_data(@project_name, 'option string') }.should_not raise_error(ArgumentError)
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should get the time data (from punch)' do
|
152
|
+
IO.expects(:read).with(regexp_matches(/^\| punch list\b/))
|
153
|
+
Freshtrack.get_time_data(@project_name)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should pass the supplied project when getting the time data' do
|
157
|
+
IO.expects(:read).with(regexp_matches(/\b#{@project_name}\b/))
|
158
|
+
Freshtrack.get_time_data(@project_name)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should pass the supplied option string on when getting the time data' do
|
162
|
+
options = 'options go here'
|
163
|
+
IO.expects(:read).with(regexp_matches(/\b#{@project_name} #{options}\b/))
|
164
|
+
Freshtrack.get_time_data(@project_name, options)
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should default option string to empty string' do
|
168
|
+
IO.expects(:read).with(regexp_matches(/\b#{@project_name} $/))
|
169
|
+
Freshtrack.get_time_data(@project_name)
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'should convert the time data' do
|
173
|
+
Freshtrack.expects(:convert_time_data).with(@time_data)
|
174
|
+
Freshtrack.get_time_data(@project_name)
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'should return the converted data' do
|
178
|
+
converted = stub('converted time data')
|
179
|
+
Freshtrack.stubs(:convert_time_data).returns(converted)
|
180
|
+
Freshtrack.get_time_data(@project_name).should == converted
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
describe 'converting time data' do
|
185
|
+
before :each do
|
186
|
+
@time_data = stub('time data')
|
187
|
+
YAML.stubs(:load)
|
188
|
+
Freshtrack.stubs(:condense_time_data)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'should require an argument' do
|
192
|
+
lambda { Freshtrack.convert_time_data }.should raise_error(ArgumentError)
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'should accept an argument' do
|
196
|
+
lambda { Freshtrack.convert_time_data(@time_data) }.should_not raise_error(ArgumentError)
|
197
|
+
end
|
198
|
+
|
199
|
+
it 'should convert the time data from YAML' do
|
200
|
+
YAML.expects(:load).with(@time_data)
|
201
|
+
Freshtrack.convert_time_data(@time_data)
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should condense the raw data' do
|
205
|
+
raw = stub('raw time data')
|
206
|
+
YAML.stubs(:load).returns(raw)
|
207
|
+
Freshtrack.expects(:condense_time_data).with(raw)
|
208
|
+
Freshtrack.convert_time_data(@project_name)
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'should return the condensed data' do
|
212
|
+
condensed = stub('condensed time data')
|
213
|
+
Freshtrack.stubs(:condense_time_data).returns(condensed)
|
214
|
+
Freshtrack.convert_time_data(@time_data).should == condensed
|
215
|
+
end
|
216
|
+
end
|
217
|
+
|
218
|
+
describe 'condensing time data' do
|
219
|
+
before :each do
|
220
|
+
@time_data = stub('time data')
|
221
|
+
Freshtrack.stubs(:times_to_dates)
|
222
|
+
Freshtrack.stubs(:group_date_data)
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'should require an argument' do
|
226
|
+
lambda { Freshtrack.condense_time_data }.should raise_error(ArgumentError)
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should accept an argument' do
|
230
|
+
lambda { Freshtrack.condense_time_data(@time_data) }.should_not raise_error(ArgumentError)
|
231
|
+
end
|
232
|
+
|
233
|
+
it 'should convert times to dates and hour differences' do
|
234
|
+
Freshtrack.expects(:times_to_dates).with(@time_data)
|
235
|
+
Freshtrack.condense_time_data(@time_data)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'should group date and hour differences' do
|
239
|
+
date_hour_data = stub('date/hour data')
|
240
|
+
Freshtrack.stubs(:times_to_dates).returns(date_hour_data)
|
241
|
+
Freshtrack.expects(:group_date_data).with(date_hour_data)
|
242
|
+
Freshtrack.condense_time_data(@time_data)
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'should return the grouped date/hour data' do
|
246
|
+
grouped_dates = stub('grouped date/hour data')
|
247
|
+
Freshtrack.stubs(:group_date_data).returns(grouped_dates)
|
248
|
+
Freshtrack.condense_time_data(@time_data).should == grouped_dates
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
describe 'converting times to dates and hour differences' do
|
253
|
+
before :each do
|
254
|
+
@time_data = []
|
255
|
+
end
|
256
|
+
|
257
|
+
it 'should require an argument' do
|
258
|
+
lambda { Freshtrack.times_to_dates }.should raise_error(ArgumentError)
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should accept an argument' do
|
262
|
+
lambda { Freshtrack.times_to_dates(@time_data) }.should_not raise_error(ArgumentError)
|
263
|
+
end
|
264
|
+
|
265
|
+
it 'should return an array' do
|
266
|
+
Freshtrack.times_to_dates(@time_data).should be_kind_of(Array)
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'should replace the in/out time data with a single date' do
|
270
|
+
@time_data.push({ 'in' => Time.local(2008, 1, 25, 6, 25, 0), 'out' => Time.local(2008, 1, 25, 7, 25, 0) })
|
271
|
+
result = Freshtrack.times_to_dates(@time_data)
|
272
|
+
result = result.first
|
273
|
+
|
274
|
+
result.should have_key('date')
|
275
|
+
result.should_not have_key('in')
|
276
|
+
result.should_not have_key('out')
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should make the date appopriate to the time' do
|
280
|
+
@time_data.push({ 'in' => Time.local(2008, 1, 25, 6, 25, 0), 'out' => Time.local(2008, 1, 25, 7, 25, 0) })
|
281
|
+
result = Freshtrack.times_to_dates(@time_data)
|
282
|
+
result = result.first
|
283
|
+
result['date'].should == Date.civil(2008, 1, 25)
|
284
|
+
end
|
285
|
+
|
286
|
+
it 'should use the in time date' do
|
287
|
+
@time_data.push({ 'in' => Time.local(2008, 1, 25, 6, 25, 0), 'out' => Time.local(2008, 1, 26, 7, 25, 0) })
|
288
|
+
result = Freshtrack.times_to_dates(@time_data)
|
289
|
+
result = result.first
|
290
|
+
result['date'].should == Date.civil(2008, 1, 25)
|
291
|
+
end
|
292
|
+
|
293
|
+
it 'should add hour data' do
|
294
|
+
@time_data.push({ 'in' => Time.local(2008, 1, 25, 6, 25, 0), 'out' => Time.local(2008, 1, 25, 7, 25, 0) })
|
295
|
+
result = Freshtrack.times_to_dates(@time_data)
|
296
|
+
result = result.first
|
297
|
+
result.should have_key('hours')
|
298
|
+
end
|
299
|
+
|
300
|
+
it 'should make the hour data appropriate to the in/out difference' do
|
301
|
+
@time_data.push({ 'in' => Time.local(2008, 1, 25, 6, 25, 0), 'out' => Time.local(2008, 1, 25, 7, 55, 0) })
|
302
|
+
result = Freshtrack.times_to_dates(@time_data)
|
303
|
+
result = result.first
|
304
|
+
result['hours'].should == 1.5
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
describe 'grouping date data' do
|
309
|
+
before :each do
|
310
|
+
@date_data = []
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'should require an argument' do
|
314
|
+
lambda { Freshtrack.group_date_data }.should raise_error(ArgumentError)
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'should accept an argument' do
|
318
|
+
lambda { Freshtrack.group_date_data(@date_data) }.should_not raise_error(ArgumentError)
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'should return an array' do
|
322
|
+
Freshtrack.group_date_data(@date_data).should be_kind_of(Array)
|
323
|
+
end
|
324
|
+
|
325
|
+
it 'should group the data by date' do
|
326
|
+
today = Date.today
|
327
|
+
@date_data.push({ 'date' => today, 'hours' => 0, 'log' => [] })
|
328
|
+
@date_data.push({ 'date' => today, 'hours' => 0, 'log' => [] })
|
329
|
+
@date_data.push({ 'date' => today + 1, 'hours' => 0, 'log' => [] })
|
330
|
+
Freshtrack.group_date_data(@date_data).collect { |x| x['date'] }.should == [today, today + 1]
|
331
|
+
end
|
332
|
+
|
333
|
+
it 'should return the array sorted by date' do
|
334
|
+
today = Date.today
|
335
|
+
@date_data.push({ 'date' => today + 1, 'hours' => 0, 'log' => [] })
|
336
|
+
@date_data.push({ 'date' => today - 1, 'hours' => 0, 'log' => [] })
|
337
|
+
@date_data.push({ 'date' => today, 'hours' => 0, 'log' => [] })
|
338
|
+
@date_data.push({ 'date' => today + 1, 'hours' => 0, 'log' => [] })
|
339
|
+
Freshtrack.group_date_data(@date_data).collect { |x| x['date'] }.should == [today - 1, today, today + 1]
|
340
|
+
end
|
341
|
+
|
342
|
+
it 'should add the hours for a particular date' do
|
343
|
+
today = Date.today
|
344
|
+
@date_data.push({ 'date' => today, 'hours' => 1, 'log' => [] })
|
345
|
+
@date_data.push({ 'date' => today, 'hours' => 3, 'log' => [] })
|
346
|
+
@date_data.push({ 'date' => today + 1, 'hours' => 2, 'log' => [] })
|
347
|
+
result = Freshtrack.group_date_data(@date_data)
|
348
|
+
|
349
|
+
result[0]['date'].should == today
|
350
|
+
result[0]['hours'].should == 4
|
351
|
+
|
352
|
+
result[1]['date'].should == today + 1
|
353
|
+
result[1]['hours'].should == 2
|
354
|
+
end
|
355
|
+
|
356
|
+
it 'should round the hours to two decimal places' do
|
357
|
+
today = Date.today
|
358
|
+
@date_data.push({ 'date' => today, 'hours' => 1.666666666, 'log' => [] })
|
359
|
+
result = Freshtrack.group_date_data(@date_data)
|
360
|
+
|
361
|
+
result[0]['date'].should == today
|
362
|
+
result[0]['hours'].should == 1.67
|
363
|
+
end
|
364
|
+
|
365
|
+
it 'should join the log into notes' do
|
366
|
+
today = Date.today
|
367
|
+
@date_data.push({ 'date' => today, 'hours' => 0, 'log' => ['punch in 1', 'punch out 1'] })
|
368
|
+
@date_data.push({ 'date' => today, 'hours' => 0, 'log' => ['punch in 2', 'punch out 2'] })
|
369
|
+
@date_data.push({ 'date' => today + 1, 'hours' => 0, 'log' => ['punch in 3', 'punch out 3'] })
|
370
|
+
result = Freshtrack.group_date_data(@date_data)
|
371
|
+
|
372
|
+
result[0]['date'].should == today
|
373
|
+
result[0]['notes'].should == "punch in 1\npunch out 1\n--------------------\npunch in 2\npunch out 2"
|
374
|
+
result[0].should_not have_key('log')
|
375
|
+
|
376
|
+
result[1]['date'].should == today + 1
|
377
|
+
result[1]['notes'].should == "punch in 3\npunch out 3"
|
378
|
+
result[1].should_not have_key('log')
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
describe 'getting data' do
|
383
|
+
before :each do
|
384
|
+
@project_name = :proj
|
385
|
+
Freshtrack.stubs(:get_project_data)
|
386
|
+
Freshtrack.stubs(:get_time_data)
|
387
|
+
end
|
388
|
+
|
389
|
+
it 'should require an argument' do
|
390
|
+
lambda { Freshtrack.get_data }.should raise_error(ArgumentError)
|
391
|
+
end
|
392
|
+
|
393
|
+
it 'should accept an argument' do
|
394
|
+
lambda { Freshtrack.get_data(@project_name) }.should_not raise_error(ArgumentError)
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'should accept an option string' do
|
398
|
+
lambda { Freshtrack.get_data(@project_name, 'option string') }.should_not raise_error(ArgumentError)
|
399
|
+
end
|
400
|
+
|
401
|
+
it 'should get project data for supplied project' do
|
402
|
+
Freshtrack.expects(:get_project_data).with(@project_name)
|
403
|
+
Freshtrack.get_data(@project_name)
|
404
|
+
end
|
405
|
+
|
406
|
+
it 'should get time data for supplied project' do
|
407
|
+
Freshtrack.expects(:get_time_data).with(@project_name, anything)
|
408
|
+
Freshtrack.get_data(@project_name)
|
409
|
+
end
|
410
|
+
|
411
|
+
it 'should pass option string on when getting time data' do
|
412
|
+
options = 'here be options'
|
413
|
+
Freshtrack.expects(:get_time_data).with(@project_name, options)
|
414
|
+
Freshtrack.get_data(@project_name, options)
|
415
|
+
end
|
416
|
+
|
417
|
+
it 'should default option string to empty string' do
|
418
|
+
Freshtrack.expects(:get_time_data).with(@project_name, '')
|
419
|
+
Freshtrack.get_data(@project_name)
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'should return time data' do
|
423
|
+
time_data = stub('time data')
|
424
|
+
Freshtrack.stubs(:get_time_data).returns(time_data)
|
425
|
+
Freshtrack.get_data(@project_name).should == time_data
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
describe 'tracking time' do
|
430
|
+
before :each do
|
431
|
+
@project_name = :proj
|
432
|
+
@data = []
|
433
|
+
Freshtrack.stubs(:get_data).returns(@data)
|
434
|
+
end
|
435
|
+
|
436
|
+
it 'should require an argument' do
|
437
|
+
lambda { Freshtrack.track }.should raise_error(ArgumentError)
|
438
|
+
end
|
439
|
+
|
440
|
+
it 'should accept an argument' do
|
441
|
+
lambda { Freshtrack.track(@project_name) }.should_not raise_error(ArgumentError)
|
442
|
+
end
|
443
|
+
|
444
|
+
it 'should accept an option string' do
|
445
|
+
lambda { Freshtrack.track(@project_name, 'option string') }.should_not raise_error(ArgumentError)
|
446
|
+
end
|
447
|
+
|
448
|
+
it 'should get data for supplied project' do
|
449
|
+
Freshtrack.expects(:get_data).with(@project_name, anything).returns(@data)
|
450
|
+
Freshtrack.track(@project_name)
|
451
|
+
end
|
452
|
+
|
453
|
+
it 'should pass option string on when getting data' do
|
454
|
+
options = 'here be options'
|
455
|
+
Freshtrack.expects(:get_data).with(@project_name, options).returns(@data)
|
456
|
+
Freshtrack.track(@project_name, options)
|
457
|
+
end
|
458
|
+
|
459
|
+
it 'should default option string to empty string' do
|
460
|
+
Freshtrack.expects(:get_data).with(@project_name, '').returns(@data)
|
461
|
+
Freshtrack.track(@project_name)
|
462
|
+
end
|
463
|
+
|
464
|
+
it 'should create entries for project data' do
|
465
|
+
2.times do
|
466
|
+
ent = stub('entry data')
|
467
|
+
@data.push(ent)
|
468
|
+
Freshtrack.expects(:create_entry).with(ent)
|
469
|
+
end
|
470
|
+
Freshtrack.track(@project_name)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
describe 'creating an entry' do
|
475
|
+
before :each do
|
476
|
+
@date = Date.today - 3
|
477
|
+
@hours = 5.67
|
478
|
+
@notes = 'notes for the time entry'
|
479
|
+
@entry_data = { 'date' => @date, 'hours' => @hours, 'notes' => @notes }
|
480
|
+
@time_entry = stub('time entry', :project_id= => nil, :task_id= => nil, :date= => nil, :hours= => nil, :notes= => nil, :create => true)
|
481
|
+
FreshBooks::TimeEntry.stubs(:new).returns(@time_entry)
|
482
|
+
|
483
|
+
@project = stub('project', :project_id => stub('project id'))
|
484
|
+
@task = stub('task', :task_id => stub('task id'))
|
485
|
+
Freshtrack.stubs(:project).returns(@project)
|
486
|
+
Freshtrack.stubs(:task).returns(@task)
|
487
|
+
|
488
|
+
STDERR.stubs(:puts)
|
489
|
+
end
|
490
|
+
|
491
|
+
it 'should require an argument' do
|
492
|
+
lambda { Freshtrack.create_entry }.should raise_error(ArgumentError)
|
493
|
+
end
|
494
|
+
|
495
|
+
it 'should accept an argument' do
|
496
|
+
lambda { Freshtrack.create_entry(@entry_data) }.should_not raise_error(ArgumentError)
|
497
|
+
end
|
498
|
+
|
499
|
+
it 'should instantiate a new time entry' do
|
500
|
+
FreshBooks::TimeEntry.expects(:new).returns(@time_entry)
|
501
|
+
Freshtrack.create_entry(@entry_data)
|
502
|
+
end
|
503
|
+
|
504
|
+
describe 'with the time entry instance' do
|
505
|
+
it 'should set the project' do
|
506
|
+
@time_entry.expects(:project_id=).with(@project.project_id)
|
507
|
+
Freshtrack.create_entry(@entry_data)
|
508
|
+
end
|
509
|
+
|
510
|
+
it 'should set the task' do
|
511
|
+
@time_entry.expects(:task_id=).with(@task.task_id)
|
512
|
+
Freshtrack.create_entry(@entry_data)
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'should set the date' do
|
516
|
+
@time_entry.expects(:date=).with(@date)
|
517
|
+
Freshtrack.create_entry(@entry_data)
|
518
|
+
end
|
519
|
+
|
520
|
+
it 'should set the hours' do
|
521
|
+
@time_entry.expects(:hours=).with(@hours)
|
522
|
+
Freshtrack.create_entry(@entry_data)
|
523
|
+
end
|
524
|
+
|
525
|
+
it 'should set the notes' do
|
526
|
+
@time_entry.expects(:notes=).with(@notes)
|
527
|
+
Freshtrack.create_entry(@entry_data)
|
528
|
+
end
|
529
|
+
end
|
530
|
+
|
531
|
+
it 'should create the time entry' do
|
532
|
+
@time_entry.expects(:create)
|
533
|
+
Freshtrack.create_entry(@entry_data)
|
534
|
+
end
|
535
|
+
|
536
|
+
describe 'successfully' do
|
537
|
+
before :each do
|
538
|
+
@time_entry.stubs(:create).returns(5)
|
539
|
+
end
|
540
|
+
|
541
|
+
it 'should be silent' do
|
542
|
+
STDERR.expects(:puts).never
|
543
|
+
Freshtrack.create_entry(@entry_data)
|
544
|
+
end
|
545
|
+
|
546
|
+
it 'should return true' do
|
547
|
+
Freshtrack.create_entry(@entry_data).should be(true)
|
548
|
+
end
|
549
|
+
end
|
550
|
+
|
551
|
+
describe 'unsuccessfully' do
|
552
|
+
before :each do
|
553
|
+
@time_entry.stubs(:create).returns(nil)
|
554
|
+
end
|
555
|
+
|
556
|
+
it 'should output an indication' do
|
557
|
+
STDERR.expects(:puts).with(regexp_matches(/#{@date.to_s}/))
|
558
|
+
Freshtrack.create_entry(@entry_data)
|
559
|
+
end
|
560
|
+
|
561
|
+
it 'should return nil' do
|
562
|
+
Freshtrack.create_entry(@entry_data).should be_nil
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Integer do
|
4
|
+
it 'should be convertible from seconds to hours' do
|
5
|
+
90.should respond_to(:secs_to_hours)
|
6
|
+
end
|
7
|
+
|
8
|
+
it 'should return this number of seconds as an amount of hours' do
|
9
|
+
90.secs_to_hours.should == 0.025
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe Float do
|
14
|
+
it 'should be convertible from seconds to hours' do
|
15
|
+
90.0.should respond_to(:secs_to_hours)
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should return this number of seconds as an amount of hours' do
|
19
|
+
90.0.secs_to_hours.should == 0.025
|
20
|
+
end
|
21
|
+
end
|