timetrap 1.15.1 → 1.15.4
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.
- checksums.yaml +5 -5
- data/.github/pull_request_template.md +29 -0
- data/.github/workflows/rspec.yml +16 -0
- data/.gitignore +1 -0
- data/.rspec +1 -2
- data/.travis.yml +6 -3
- data/CONTRIBUTORS +1 -0
- data/README.md +39 -6
- data/completions/bash/timetrap-autocomplete.bash +2 -1
- data/lib/timetrap/cli.rb +24 -5
- data/lib/timetrap/formatters/csv.rb +5 -1
- data/lib/timetrap/formatters/ical.rb +8 -16
- data/lib/timetrap/formatters/json.rb +6 -1
- data/lib/timetrap/helpers.rb +6 -6
- data/lib/timetrap/models.rb +1 -20
- data/lib/timetrap/schema.rb +47 -0
- data/lib/timetrap/version.rb +1 -1
- data/lib/timetrap.rb +6 -2
- data/spec/spec_helper.rb +40 -0
- data/spec/support/local_time.rb +7 -0
- data/spec/support/with_rounding_on.rb +9 -0
- data/spec/support/with_stubbed_config.rb +7 -0
- data/spec/timetrap_spec.rb +318 -300
- data/timetrap.gemspec +9 -9
- metadata +58 -47
data/spec/timetrap_spec.rb
CHANGED
@@ -1,43 +1,8 @@
|
|
1
|
-
TEST_MODE = true
|
2
|
-
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'timetrap'))
|
3
|
-
require 'rspec'
|
4
|
-
require 'fakefs/safe'
|
5
|
-
|
6
|
-
RSpec.configure do |config|
|
7
|
-
# as we are stubbing stderr and stdout, if you want to capture
|
8
|
-
# any of your output in tests, simply add :write_stdout_stderr => true
|
9
|
-
# as metadata to the end of your test
|
10
|
-
config.after(:each, write_stdout_stderr: true) do
|
11
|
-
$stderr.rewind
|
12
|
-
$stdout.rewind
|
13
|
-
File.write("stderr.txt", $stderr.read)
|
14
|
-
File.write("stdout.txt", $stdout.read)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def local_time(str)
|
19
|
-
Timetrap::Timer.process_time(str)
|
20
|
-
end
|
21
|
-
|
22
|
-
def local_time_cli(str)
|
23
|
-
local_time(str).strftime('%Y-%m-%d %H:%M:%S')
|
24
|
-
end
|
25
|
-
|
26
|
-
module Timetrap::StubConfig
|
27
|
-
def with_stubbed_config options = {}
|
28
|
-
defaults = Timetrap::Config.defaults.dup
|
29
|
-
Timetrap::Config.stub(:[]) do |k|
|
30
|
-
defaults.merge(options)[k]
|
31
|
-
end
|
32
|
-
yield if block_given?
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
1
|
describe Timetrap do
|
37
|
-
include Timetrap::StubConfig
|
38
2
|
before do
|
39
3
|
with_stubbed_config
|
40
4
|
end
|
5
|
+
|
41
6
|
def create_entry atts = {}
|
42
7
|
Timetrap::Entry.create({
|
43
8
|
:sheet => 'default',
|
@@ -46,10 +11,9 @@ describe Timetrap do
|
|
46
11
|
:note => 'note'}.merge(atts))
|
47
12
|
end
|
48
13
|
|
49
|
-
|
50
14
|
before :each do
|
51
|
-
Timetrap::
|
52
|
-
Timetrap::
|
15
|
+
Timetrap::EntrySchema.create_table!
|
16
|
+
Timetrap::MetaSchema.create_table!
|
53
17
|
$stdout = StringIO.new
|
54
18
|
$stdin = StringIO.new
|
55
19
|
$stderr = StringIO.new
|
@@ -66,7 +30,7 @@ describe Timetrap do
|
|
66
30
|
it "should invoke --help" do
|
67
31
|
with_stubbed_config('default_command' => nil) do
|
68
32
|
invoke ''
|
69
|
-
$stdout.string.
|
33
|
+
expect($stdout.string).to include "Usage"
|
70
34
|
end
|
71
35
|
end
|
72
36
|
end
|
@@ -75,7 +39,7 @@ describe Timetrap do
|
|
75
39
|
it "should invoke the default command" do
|
76
40
|
with_stubbed_config('default_command' => 'n') do
|
77
41
|
invoke ''
|
78
|
-
$stderr.string.
|
42
|
+
expect($stderr.string).to include('*default: not running')
|
79
43
|
end
|
80
44
|
end
|
81
45
|
|
@@ -84,7 +48,7 @@ describe Timetrap do
|
|
84
48
|
invoke 'in foo bar'
|
85
49
|
invoke 'out'
|
86
50
|
invoke ''
|
87
|
-
$stdout.string.
|
51
|
+
expect($stdout.string).to include(',"foo bar"')
|
88
52
|
end
|
89
53
|
end
|
90
54
|
end
|
@@ -92,7 +56,7 @@ describe Timetrap do
|
|
92
56
|
describe 'with an invalid command' do
|
93
57
|
it "should tell me I'm wrong" do
|
94
58
|
invoke 'poo'
|
95
|
-
$stderr.string.
|
59
|
+
expect($stderr.string).to include 'Invalid command: "poo"'
|
96
60
|
end
|
97
61
|
end
|
98
62
|
|
@@ -112,9 +76,9 @@ describe Timetrap do
|
|
112
76
|
invoke 'archive --grep [g][r][e][p]'
|
113
77
|
Timetrap::Entry.each do |e|
|
114
78
|
if e.note == 'grep'
|
115
|
-
e.sheet.
|
79
|
+
expect(e.sheet).to eq '_default'
|
116
80
|
else
|
117
|
-
e.sheet.
|
81
|
+
expect(e.sheet).to eq 'default'
|
118
82
|
end
|
119
83
|
end
|
120
84
|
end
|
@@ -123,7 +87,7 @@ describe Timetrap do
|
|
123
87
|
$stdin.string = "yes\n"
|
124
88
|
invoke 'archive'
|
125
89
|
Timetrap::Entry.each do |e|
|
126
|
-
e.sheet.
|
90
|
+
expect(e.sheet).to eq '_default'
|
127
91
|
end
|
128
92
|
end
|
129
93
|
|
@@ -131,7 +95,7 @@ describe Timetrap do
|
|
131
95
|
invoke "in"
|
132
96
|
$stdin.string = "yes\n"
|
133
97
|
invoke 'archive'
|
134
|
-
Timetrap::Entry.order(:id).last.sheet.
|
98
|
+
expect(Timetrap::Entry.order(:id).last.sheet).to eq 'default'
|
135
99
|
end
|
136
100
|
end
|
137
101
|
|
@@ -141,16 +105,16 @@ describe Timetrap do
|
|
141
105
|
FileUtils.mkdir_p(ENV['HOME'])
|
142
106
|
config_file = ENV['HOME'] + '/.timetrap.yml'
|
143
107
|
FileUtils.rm(config_file) if File.exist? config_file
|
144
|
-
File.exist?(config_file).
|
108
|
+
expect(File.exist?(config_file)).to be_falsey
|
145
109
|
invoke "configure"
|
146
|
-
File.exist?(config_file).
|
110
|
+
expect(File.exist?(config_file)).to be_truthy
|
147
111
|
end
|
148
112
|
end
|
149
113
|
|
150
114
|
it "should describe config file" do
|
151
115
|
FakeFS do
|
152
116
|
invoke "configure"
|
153
|
-
$stdout.string.
|
117
|
+
expect($stdout.string).to eq "Config file is at \"#{ENV['HOME']}/.timetrap.yml\"\n"
|
154
118
|
end
|
155
119
|
end
|
156
120
|
end
|
@@ -161,23 +125,23 @@ describe Timetrap do
|
|
161
125
|
end
|
162
126
|
|
163
127
|
it "should edit the description of the active period" do
|
164
|
-
Timetrap::Timer.active_entry.note.
|
128
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
165
129
|
invoke 'edit new description'
|
166
|
-
Timetrap::Timer.active_entry.note.
|
130
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'new description'
|
167
131
|
end
|
168
132
|
|
169
133
|
it "should allow you to move an entry to another sheet" do
|
170
134
|
invoke 'edit --move blahblah'
|
171
|
-
Timetrap::Timer.active_entry[:sheet].
|
135
|
+
expect(Timetrap::Timer.active_entry[:sheet]).to eq 'blahblah'
|
172
136
|
invoke 'edit -m blahblahblah'
|
173
|
-
Timetrap::Timer.active_entry[:sheet].
|
137
|
+
expect(Timetrap::Timer.active_entry[:sheet]).to eq 'blahblahblah'
|
174
138
|
end
|
175
139
|
|
176
140
|
it "should change the current sheet if the current entry's sheet is changed" do
|
177
|
-
Timetrap::Timer.current_sheet.
|
141
|
+
expect(Timetrap::Timer.current_sheet).not_to eq 'blahblahblah'
|
178
142
|
invoke 'edit -m blahblahblah'
|
179
|
-
Timetrap::Timer.active_entry[:sheet].
|
180
|
-
Timetrap::Timer.current_sheet.
|
143
|
+
expect(Timetrap::Timer.active_entry[:sheet]).to eq 'blahblahblah'
|
144
|
+
expect(Timetrap::Timer.current_sheet).to eq 'blahblahblah'
|
181
145
|
end
|
182
146
|
|
183
147
|
it "should change the current sheet if a non current entry's sheet is changed" do
|
@@ -185,30 +149,40 @@ describe Timetrap do
|
|
185
149
|
id = Timetrap::Timer.active_entry[:id]
|
186
150
|
invoke 'out'
|
187
151
|
invoke "edit -m blahblahblah -i #{id}"
|
188
|
-
Timetrap::Timer.current_sheet.
|
189
|
-
Timetrap::Entry[id][:sheet].
|
152
|
+
expect(Timetrap::Timer.current_sheet).to eq sheet
|
153
|
+
expect(Timetrap::Entry[id][:sheet]).to eq 'blahblahblah'
|
190
154
|
end
|
191
155
|
|
192
156
|
it "should allow appending to the description of the active period" do
|
193
157
|
with_stubbed_config('append_notes_delimiter' => '//')
|
194
|
-
Timetrap::Timer.active_entry.note.
|
158
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
195
159
|
invoke 'edit --append new'
|
196
|
-
Timetrap::Timer.active_entry.note.
|
160
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry//new'
|
197
161
|
invoke 'edit -z more'
|
198
|
-
Timetrap::Timer.active_entry.note.
|
162
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry//new//more'
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should allow clearing the description of the active period" do
|
166
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
167
|
+
invoke 'edit --clear'
|
168
|
+
expect(Timetrap::Timer.active_entry.note).to eq ''
|
169
|
+
invoke 'edit running entry'
|
170
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
171
|
+
invoke 'edit -c'
|
172
|
+
expect(Timetrap::Timer.active_entry.note).to eq ''
|
199
173
|
end
|
200
174
|
|
201
175
|
it "should edit the start time of the active period" do
|
202
176
|
invoke 'edit --start "yesterday 10am"'
|
203
|
-
Timetrap::Timer.active_entry.start.
|
204
|
-
Timetrap::Timer.active_entry.note.
|
177
|
+
expect(Timetrap::Timer.active_entry.start).to eq Chronic.parse("yesterday 10am")
|
178
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
205
179
|
end
|
206
180
|
|
207
181
|
it "should edit the end time of the active period" do
|
208
182
|
entry = Timetrap::Timer.active_entry
|
209
183
|
invoke 'edit --end "yesterday 10am"'
|
210
|
-
entry.refresh.end.
|
211
|
-
entry.refresh.note.
|
184
|
+
expect(entry.refresh.end).to eq Chronic.parse("yesterday 10am")
|
185
|
+
expect(entry.refresh.note).to eq 'running entry'
|
212
186
|
end
|
213
187
|
|
214
188
|
it "should edit a non running entry based on id" do
|
@@ -225,14 +199,14 @@ describe Timetrap do
|
|
225
199
|
Timetrap::Timer.start "another entry", nil
|
226
200
|
|
227
201
|
invoke "edit --id #{not_running.id} a new description"
|
228
|
-
not_running.refresh.note.
|
202
|
+
expect(not_running.refresh.note).to eq 'a new description'
|
229
203
|
end
|
230
204
|
|
231
205
|
it "should edit the entry last checked out of if none is running" do
|
232
206
|
not_running = Timetrap::Timer.active_entry
|
233
207
|
Timetrap::Timer.stop(Timetrap::Timer.current_sheet)
|
234
208
|
invoke "edit -z 'a new description'"
|
235
|
-
not_running.refresh.note.
|
209
|
+
expect(not_running.refresh.note).to include 'a new description'
|
236
210
|
end
|
237
211
|
|
238
212
|
it "should edit the entry last checked out of if none is running even if the sheet is changed" do
|
@@ -240,9 +214,9 @@ describe Timetrap do
|
|
240
214
|
Timetrap::Timer.stop(Timetrap::Timer.current_sheet)
|
241
215
|
invoke "edit -z 'a new description'"
|
242
216
|
invoke "sheet another second sheet"
|
243
|
-
not_running.refresh.note.
|
244
|
-
not_running.refresh.sheet.
|
245
|
-
Timetrap::Timer.current_sheet.
|
217
|
+
expect(not_running.refresh.note).to include 'a new description'
|
218
|
+
expect(not_running.refresh.sheet).to eq 'default'
|
219
|
+
expect(Timetrap::Timer.current_sheet).to eq 'another second sheet'
|
246
220
|
end
|
247
221
|
|
248
222
|
context "with external editor" do
|
@@ -253,18 +227,18 @@ describe Timetrap do
|
|
253
227
|
end
|
254
228
|
|
255
229
|
it "should open an editor for editing the note" do |example|
|
256
|
-
Timetrap::CLI.
|
230
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
257
231
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
258
232
|
File.write(path[:path], "edited note")
|
259
233
|
end
|
260
|
-
Timetrap::Timer.active_entry.note.
|
234
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
261
235
|
invoke "edit"
|
262
|
-
Timetrap::Timer.active_entry.note.
|
236
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'edited note'
|
263
237
|
end
|
264
238
|
|
265
239
|
it "should pass existing note to editor" do |example|
|
266
240
|
capture = nil
|
267
|
-
Timetrap::CLI.
|
241
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
268
242
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
269
243
|
|
270
244
|
capture = File.read(path[:path])
|
@@ -286,14 +260,14 @@ describe Timetrap do
|
|
286
260
|
|
287
261
|
Timetrap::Timer.stop(Timetrap::Timer.current_sheet)
|
288
262
|
|
289
|
-
Timetrap::CLI.
|
263
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
290
264
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
291
265
|
File.write(path[:path], "id passed note")
|
292
266
|
end
|
293
267
|
|
294
268
|
invoke "edit --id #{not_running.id}"
|
295
269
|
|
296
|
-
not_running.refresh.note.
|
270
|
+
expect(not_running.refresh.note).to eq "id passed note"
|
297
271
|
end
|
298
272
|
|
299
273
|
it "should not call the editor if there are arguments other than --id" do
|
@@ -308,23 +282,37 @@ describe Timetrap do
|
|
308
282
|
|
309
283
|
context "appending" do
|
310
284
|
it "should open an editor for editing the note with -z" do |example|
|
311
|
-
Timetrap::CLI.
|
285
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
312
286
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
313
287
|
File.write(path[:path], "appended in editor")
|
314
288
|
end
|
315
|
-
Timetrap::Timer.active_entry.note.
|
289
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
316
290
|
invoke "edit -z"
|
317
|
-
Timetrap::Timer.active_entry.note.
|
291
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry//appended in editor'
|
318
292
|
end
|
319
293
|
|
320
294
|
it "should open a editor for editing the note with --append" do |example|
|
321
|
-
Timetrap::CLI.
|
295
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
322
296
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
323
297
|
File.write(path[:path], "appended in editor")
|
324
298
|
end
|
325
|
-
Timetrap::Timer.active_entry.note.
|
299
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
326
300
|
invoke "edit --append"
|
327
|
-
Timetrap::Timer.active_entry.note.
|
301
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry//appended in editor'
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context "clearing" do
|
306
|
+
it "should clear the last entry with -c" do
|
307
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
308
|
+
invoke "edit -c"
|
309
|
+
expect(Timetrap::Timer.active_entry.note).to eq ''
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should clear the last entry with --clear" do
|
313
|
+
expect(Timetrap::Timer.active_entry.note).to eq 'running entry'
|
314
|
+
invoke "edit --clear"
|
315
|
+
expect(Timetrap::Timer.active_entry.note).to eq ''
|
328
316
|
end
|
329
317
|
end
|
330
318
|
end
|
@@ -336,7 +324,7 @@ describe Timetrap do
|
|
336
324
|
it 'should use sheet defined in dotfile' do
|
337
325
|
Dir.chdir('spec/dotfile') do
|
338
326
|
with_stubbed_config('auto_sheet' => 'dotfiles')
|
339
|
-
Timetrap::Timer.current_sheet.
|
327
|
+
expect(Timetrap::Timer.current_sheet).to eq 'dotfile-sheet'
|
340
328
|
end
|
341
329
|
end
|
342
330
|
end
|
@@ -349,7 +337,7 @@ describe Timetrap do
|
|
349
337
|
'auto_sheet_paths' => {
|
350
338
|
'a sheet' => ['/not/cwd/', Dir.getwd]
|
351
339
|
}, 'auto_sheet' => 'yaml_cwd')
|
352
|
-
Timetrap::Timer.current_sheet.
|
340
|
+
expect(Timetrap::Timer.current_sheet).to eq 'a sheet'
|
353
341
|
end
|
354
342
|
end
|
355
343
|
|
@@ -359,7 +347,7 @@ describe Timetrap do
|
|
359
347
|
'auto_sheet_paths' => {'a sheet' => '/'},
|
360
348
|
'auto_sheet' => 'yaml_cwd'
|
361
349
|
)
|
362
|
-
Timetrap::Timer.current_sheet.
|
350
|
+
expect(Timetrap::Timer.current_sheet).to eq 'a sheet'
|
363
351
|
end
|
364
352
|
end
|
365
353
|
|
@@ -369,7 +357,7 @@ describe Timetrap do
|
|
369
357
|
'auto_sheet_paths' => {
|
370
358
|
'a sheet' => '/not/the/current/working/directory/'
|
371
359
|
},'auto_sheet' => 'yaml_cwd')
|
372
|
-
Timetrap::Timer.current_sheet.
|
360
|
+
expect(Timetrap::Timer.current_sheet).to eq 'default'
|
373
361
|
end
|
374
362
|
end
|
375
363
|
|
@@ -379,12 +367,12 @@ describe Timetrap do
|
|
379
367
|
'auto_sheet_paths' => {
|
380
368
|
'general sheet' => '/', 'more specific sheet' => Dir.getwd
|
381
369
|
}, 'auto_sheet' => 'yaml_cwd')
|
382
|
-
Timetrap::Timer.current_sheet.
|
370
|
+
expect(Timetrap::Timer.current_sheet).to eq 'more specific sheet'
|
383
371
|
with_stubbed_config(
|
384
372
|
'auto_sheet_paths' => {
|
385
373
|
'more specific sheet' => Dir.getwd, 'general sheet' => '/'
|
386
374
|
}, 'auto_sheet' => 'yaml_cwd')
|
387
|
-
Timetrap::Timer.current_sheet.
|
375
|
+
expect(Timetrap::Timer.current_sheet).to eq 'more specific sheet'
|
388
376
|
end
|
389
377
|
end
|
390
378
|
end
|
@@ -394,13 +382,13 @@ describe Timetrap do
|
|
394
382
|
it 'should use sheet defined in dotfile' do
|
395
383
|
Dir.chdir('spec/dotfile') do
|
396
384
|
with_stubbed_config('auto_sheet' => 'nested_dotfiles')
|
397
|
-
Timetrap::Timer.current_sheet.
|
385
|
+
expect(Timetrap::Timer.current_sheet).to eq 'dotfile-sheet'
|
398
386
|
end
|
399
387
|
end
|
400
388
|
it 'should use top-most sheet found in dir heirarchy' do
|
401
389
|
Dir.chdir('spec/dotfile/nested') do
|
402
390
|
with_stubbed_config('auto_sheet' => 'nested_dotfiles')
|
403
|
-
Timetrap::Timer.current_sheet.
|
391
|
+
expect(Timetrap::Timer.current_sheet).to eq 'nested-sheet'
|
404
392
|
end
|
405
393
|
end
|
406
394
|
end
|
@@ -409,7 +397,7 @@ describe Timetrap do
|
|
409
397
|
it 'should use sheet defined in ancestor\'s dotfile' do
|
410
398
|
Dir.chdir('spec/dotfile/nested/no-sheet') do
|
411
399
|
with_stubbed_config('auto_sheet' => 'nested_dotfiles')
|
412
|
-
Timetrap::Timer.current_sheet.
|
400
|
+
expect(Timetrap::Timer.current_sheet).to eq 'nested-sheet'
|
413
401
|
end
|
414
402
|
end
|
415
403
|
end
|
@@ -418,7 +406,7 @@ describe Timetrap do
|
|
418
406
|
|
419
407
|
describe "backend" do
|
420
408
|
it "should open an sqlite console to the db" do
|
421
|
-
Timetrap::CLI.
|
409
|
+
expect(Timetrap::CLI).to receive(:exec).with("sqlite3 #{Timetrap::DB_NAME}")
|
422
410
|
invoke 'backend'
|
423
411
|
end
|
424
412
|
end
|
@@ -429,7 +417,7 @@ describe Timetrap do
|
|
429
417
|
end
|
430
418
|
it "should be deprecated" do
|
431
419
|
invoke 'format'
|
432
|
-
$stderr.string.
|
420
|
+
expect($stderr.string).to eq <<-WARN
|
433
421
|
The "format" command is deprecated in favor of "display". Sorry for the inconvenience.
|
434
422
|
WARN
|
435
423
|
end
|
@@ -461,7 +449,7 @@ The "format" command is deprecated in favor of "display". Sorry for the inconven
|
|
461
449
|
)
|
462
450
|
|
463
451
|
now = local_time('2008-10-05 20:00:00')
|
464
|
-
Time.
|
452
|
+
allow(Time).to receive(:now).and_return now
|
465
453
|
@desired_output = <<-OUTPUT
|
466
454
|
Timesheet: SpecSheet
|
467
455
|
Day Start End Duration Notes
|
@@ -555,19 +543,19 @@ Timesheet: SheetWithLineBreakNote
|
|
555
543
|
it "should display the current timesheet" do
|
556
544
|
Timetrap::Timer.current_sheet = 'SpecSheet'
|
557
545
|
invoke 'display'
|
558
|
-
$stdout.string.
|
546
|
+
expect($stdout.string).to eq @desired_output
|
559
547
|
end
|
560
548
|
|
561
549
|
it "should display a non current timesheet" do
|
562
550
|
Timetrap::Timer.current_sheet = 'another'
|
563
551
|
invoke 'display SpecSheet'
|
564
|
-
$stdout.string.
|
552
|
+
expect($stdout.string).to eq @desired_output
|
565
553
|
end
|
566
554
|
|
567
555
|
it "should display a non current timesheet based on a partial name match" do
|
568
556
|
Timetrap::Timer.current_sheet = 'another'
|
569
557
|
invoke 'display S'
|
570
|
-
$stdout.string.
|
558
|
+
expect($stdout.string).to eq @desired_output
|
571
559
|
end
|
572
560
|
|
573
561
|
it "should prefer an exact match of a named sheet to a partial match" do
|
@@ -576,50 +564,50 @@ Timesheet: SheetWithLineBreakNote
|
|
576
564
|
:note => 'entry 5', :start => '2008-10-05 18:00:00'
|
577
565
|
)
|
578
566
|
invoke 'display Spec'
|
579
|
-
$stdout.string.
|
567
|
+
expect($stdout.string).to include("entry 5")
|
580
568
|
end
|
581
569
|
|
582
570
|
it "should only display entries that are matched by the provided regex" do
|
583
571
|
Timetrap::Timer.current_sheet = 'SpecSheet'
|
584
572
|
invoke 'display --grep [13]'
|
585
|
-
$stdout.string.
|
573
|
+
expect($stdout.string).to eq @desired_output_grepped
|
586
574
|
end
|
587
575
|
|
588
576
|
it "should display a timesheet with ids" do
|
589
577
|
invoke 'display S --ids'
|
590
|
-
$stdout.string.
|
578
|
+
expect($stdout.string).to eq @desired_output_with_ids
|
591
579
|
end
|
592
580
|
|
593
581
|
it "should properly format a timesheet with long ids" do
|
594
582
|
Timetrap::DB["UPDATE entries SET id = 40000 WHERE id = 4"].all
|
595
583
|
invoke 'display S --ids'
|
596
|
-
$stdout.string.
|
584
|
+
expect($stdout.string).to eq @desired_output_with_long_ids
|
597
585
|
end
|
598
586
|
|
599
587
|
it "should properly format a timesheet with no ids even if long ids are in the db" do
|
600
588
|
Timetrap::DB["UPDATE entries SET id = 40000 WHERE id = 4"].all
|
601
589
|
invoke 'display S'
|
602
|
-
$stdout.string.
|
590
|
+
expect($stdout.string).to eq @desired_output
|
603
591
|
end
|
604
592
|
|
605
593
|
|
606
594
|
it "should display long notes nicely" do
|
607
595
|
Timetrap::Timer.current_sheet = 'LongNoteSheet'
|
608
596
|
invoke 'display'
|
609
|
-
$stdout.string.
|
597
|
+
expect($stdout.string).to eq @desired_output_for_long_note_sheet
|
610
598
|
end
|
611
599
|
|
612
600
|
it "should display long notes with linebreaks nicely" do
|
613
601
|
Timetrap::Timer.current_sheet = 'SheetWithLineBreakNote'
|
614
602
|
invoke 'display'
|
615
|
-
$stdout.string.
|
603
|
+
expect($stdout.string).to eq @desired_output_for_note_with_linebreak
|
616
604
|
end
|
617
605
|
|
618
606
|
it "should display long notes with ids nicely" do
|
619
607
|
Timetrap::DB["UPDATE entries SET id = 60000 WHERE id = 6"].all
|
620
608
|
Timetrap::Timer.current_sheet = 'LongNoteSheet'
|
621
609
|
invoke 'display --ids'
|
622
|
-
$stdout.string.
|
610
|
+
expect($stdout.string).to eq @desired_output_for_long_note_sheet_with_ids
|
623
611
|
end
|
624
612
|
|
625
613
|
it "should not display archived for all timesheets" do
|
@@ -627,7 +615,7 @@ Timesheet: SheetWithLineBreakNote
|
|
627
615
|
invoke 'archive SpecSheet'
|
628
616
|
$stdout.string = ''
|
629
617
|
invoke 'display all'
|
630
|
-
$stdout.string.
|
618
|
+
expect($stdout.string).not_to match /_SpecSheet/
|
631
619
|
end
|
632
620
|
|
633
621
|
it "it should find a user provided formatter class and require it" do
|
@@ -647,7 +635,7 @@ Timesheet: SheetWithLineBreakNote
|
|
647
635
|
RUBY
|
648
636
|
end
|
649
637
|
invoke 'd -fbaz'
|
650
|
-
$stdout.string.
|
638
|
+
expect($stdout.string).to eq "yeah I did it\n"
|
651
639
|
FileUtils.rm_r dir
|
652
640
|
end
|
653
641
|
|
@@ -657,7 +645,7 @@ Timesheet: SheetWithLineBreakNote
|
|
657
645
|
)
|
658
646
|
invoke 'd SpecSheet'
|
659
647
|
# check it doesn't error and produces valid looking output
|
660
|
-
$stdout.string.
|
648
|
+
expect($stdout.string).to include('Timesheet: SpecSheet')
|
661
649
|
end
|
662
650
|
end
|
663
651
|
|
@@ -672,7 +660,7 @@ Timesheet: SheetWithLineBreakNote
|
|
672
660
|
'formatter_search_paths' => nil
|
673
661
|
|
674
662
|
invoke 'd'
|
675
|
-
$stdout.string.
|
663
|
+
expect($stdout.string).to eq Timetrap::Entry.all.map(&:id).join(" ") + "\n"
|
676
664
|
end
|
677
665
|
end
|
678
666
|
|
@@ -685,7 +673,7 @@ Timesheet: SheetWithLineBreakNote
|
|
685
673
|
it "should not export running items" do
|
686
674
|
invoke 'in'
|
687
675
|
invoke 'display --format ids'
|
688
|
-
$stdout.string.
|
676
|
+
expect($stdout.string).to eq Timetrap::Entry.all.map(&:id).join(" ") + "\n"
|
689
677
|
end
|
690
678
|
|
691
679
|
end
|
@@ -699,7 +687,7 @@ Timesheet: SheetWithLineBreakNote
|
|
699
687
|
it "should not export running items" do
|
700
688
|
invoke 'in'
|
701
689
|
invoke 'display --format csv'
|
702
|
-
$stdout.string.
|
690
|
+
expect($stdout.string).to eq <<-EOF
|
703
691
|
start,end,note,sheet
|
704
692
|
"2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
|
705
693
|
"2008-10-05 12:00:00","2008-10-05 14:00:00","note","default"
|
@@ -708,7 +696,7 @@ start,end,note,sheet
|
|
708
696
|
|
709
697
|
it "should filter events by the passed dates" do
|
710
698
|
invoke 'display --format csv --start 2008-10-03 --end 2008-10-03'
|
711
|
-
$stdout.string.
|
699
|
+
expect($stdout.string).to eq <<-EOF
|
712
700
|
start,end,note,sheet
|
713
701
|
"2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
|
714
702
|
EOF
|
@@ -716,27 +704,54 @@ start,end,note,sheet
|
|
716
704
|
|
717
705
|
it "should not filter events by date when none are passed" do
|
718
706
|
invoke 'display --format csv'
|
719
|
-
$stdout.string.
|
707
|
+
expect($stdout.string).to eq <<-EOF
|
720
708
|
start,end,note,sheet
|
721
709
|
"2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
|
722
710
|
"2008-10-05 12:00:00","2008-10-05 14:00:00","note","default"
|
723
711
|
EOF
|
724
712
|
end
|
713
|
+
|
714
|
+
it "should escape quoted notes" do
|
715
|
+
create_entry(
|
716
|
+
:start => local_time_cli('2008-10-07 12:00:00'),
|
717
|
+
:end => local_time_cli('2008-10-07 14:00:00'),
|
718
|
+
:note => %q{"note"}
|
719
|
+
)
|
720
|
+
invoke 'display --format csv'
|
721
|
+
expect($stdout.string).to eq <<-EOF
|
722
|
+
start,end,note,sheet
|
723
|
+
"2008-10-03 12:00:00","2008-10-03 14:00:00","note","default"
|
724
|
+
"2008-10-05 12:00:00","2008-10-05 14:00:00","note","default"
|
725
|
+
"2008-10-07 12:00:00","2008-10-07 14:00:00","""note""","default"
|
726
|
+
EOF
|
727
|
+
end
|
725
728
|
end
|
726
729
|
|
727
730
|
describe 'json' do
|
728
731
|
before do
|
729
|
-
create_entry(:start => local_time_cli('2008-10-03 12:
|
732
|
+
create_entry(:start => local_time_cli('2008-10-03 12:07:00'), :end => local_time_cli('2008-10-03 14:08:00'))
|
730
733
|
create_entry(:start => local_time_cli('2008-10-05 12:00:00'), :end => local_time_cli('2008-10-05 14:00:00'))
|
731
734
|
end
|
732
735
|
|
733
736
|
it "should export to json not including running items" do
|
734
737
|
invoke 'in'
|
735
738
|
invoke 'display -f json'
|
736
|
-
JSON.parse($stdout.string).
|
737
|
-
[{\"sheet\":\"default\",\"end\":\"#{local_time('2008-10-03 14:
|
739
|
+
expect(JSON.parse($stdout.string)).to eq JSON.parse(<<-EOF)
|
740
|
+
[{\"sheet\":\"default\",\"end\":\"#{local_time('2008-10-03 14:08:00')}\",\"start\":\"#{local_time('2008-10-03 12:07:00')}\",\"note\":\"note\",\"id\":1},{\"sheet\":\"default\",\"end\":\"#{local_time('2008-10-05 14:00:00')}\",\"start\":\"#{local_time('2008-10-05 12:00:00')}\",\"note\":\"note\",\"id\":2}]
|
738
741
|
EOF
|
739
742
|
end
|
743
|
+
|
744
|
+
context 'with rounding on' do
|
745
|
+
it 'should export to json with rounded output' do
|
746
|
+
with_rounding_on do
|
747
|
+
# rounds to 900s by default
|
748
|
+
invoke 'display -r -f json'
|
749
|
+
expect(JSON.parse($stdout.string)).to eq JSON.parse(<<~EOF)
|
750
|
+
[{\"sheet\":\"default\",\"end\":\"#{local_time('2008-10-03 14:15:00')}\",\"start\":\"#{local_time('2008-10-03 12:00:00')}\",\"note\":\"note\",\"id\":1},{\"sheet\":\"default\",\"end\":\"#{local_time('2008-10-05 14:00:00')}\",\"start\":\"#{local_time('2008-10-05 12:00:00')}\",\"note\":\"note\",\"id\":2}]
|
751
|
+
EOF
|
752
|
+
end
|
753
|
+
end
|
754
|
+
end
|
740
755
|
end
|
741
756
|
|
742
757
|
describe 'ical' do
|
@@ -769,9 +784,8 @@ BEGIN:VCALENDAR
|
|
769
784
|
VERSION:2.0
|
770
785
|
CALSCALE:GREGORIAN
|
771
786
|
METHOD:PUBLISH
|
772
|
-
PRODID:
|
787
|
+
PRODID:icalendar-ruby
|
773
788
|
BEGIN:VEVENT
|
774
|
-
SEQUENCE:0
|
775
789
|
DTEND:20081003T140000
|
776
790
|
SUMMARY:note
|
777
791
|
DTSTART:20081003T120000
|
@@ -779,7 +793,7 @@ END:VEVENT
|
|
779
793
|
END:VCALENDAR
|
780
794
|
EOF
|
781
795
|
desired.each_line do |line|
|
782
|
-
$stdout.string.
|
796
|
+
expect($stdout.string).to match /#{line.chomp}/
|
783
797
|
end
|
784
798
|
end
|
785
799
|
end
|
@@ -787,49 +801,50 @@ END:VCALENDAR
|
|
787
801
|
|
788
802
|
describe "in" do
|
789
803
|
it "should start the time for the current timesheet" do
|
790
|
-
|
791
|
-
|
792
|
-
|
804
|
+
expect(
|
805
|
+
lambda do
|
806
|
+
invoke 'in'
|
807
|
+
end).to change(Timetrap::Entry, :count).by(1)
|
793
808
|
end
|
794
809
|
|
795
810
|
it "should set the note when starting a new entry" do
|
796
811
|
invoke 'in working on something'
|
797
|
-
Timetrap::Entry.order_by(:id).last.note.
|
812
|
+
expect(Timetrap::Entry.order_by(:id).last.note).to eq 'working on something'
|
798
813
|
end
|
799
814
|
|
800
815
|
it "should set the start when starting a new entry" do
|
801
816
|
@time = Time.now
|
802
|
-
Time.
|
817
|
+
allow(Time).to receive(:now).and_return @time
|
803
818
|
invoke 'in working on something'
|
804
|
-
Timetrap::Entry.order_by(:id).last.start.to_i.
|
819
|
+
expect(Timetrap::Entry.order_by(:id).last.start.to_i).to eq @time.to_i
|
805
820
|
end
|
806
821
|
|
807
822
|
it "should not start the time if the timetrap is running" do
|
808
|
-
Timetrap::Timer.
|
809
|
-
lambda do
|
823
|
+
allow(Timetrap::Timer).to receive(:running?).and_return true
|
824
|
+
expect(lambda do
|
810
825
|
invoke 'in'
|
811
|
-
|
826
|
+
end).not_to change(Timetrap::Entry, :count)
|
812
827
|
end
|
813
828
|
|
814
829
|
it "should allow the sheet to be started at a certain time" do
|
815
830
|
invoke 'in work --at "10am 2008-10-03"'
|
816
|
-
Timetrap::Entry.order_by(:id).last.start.
|
831
|
+
expect(Timetrap::Entry.order_by(:id).last.start).to eq Time.parse('2008-10-03 10:00')
|
817
832
|
end
|
818
833
|
|
819
834
|
it "should fail with a warning for misformatted cli options it can't parse" do
|
820
835
|
now = Time.now
|
821
|
-
Time.
|
836
|
+
allow(Time).to receive(:now).and_return now
|
822
837
|
invoke 'in work --at="18 minutes ago"'
|
823
|
-
Timetrap::Entry.order_by(:id).last.
|
824
|
-
$stderr.string.
|
838
|
+
expect(Timetrap::Entry.order_by(:id).last).to be_nil
|
839
|
+
expect($stderr.string).to match /\w+/
|
825
840
|
end
|
826
841
|
|
827
842
|
it "should fail with a time argurment of total garbage" do
|
828
843
|
now = Time.now
|
829
|
-
Time.
|
844
|
+
allow(Time).to receive(:now).and_return now
|
830
845
|
invoke 'in work --at "total garbage"'
|
831
|
-
Timetrap::Entry.order_by(:id).last.
|
832
|
-
$stderr.string.
|
846
|
+
expect(Timetrap::Entry.order_by(:id).last).to be_nil
|
847
|
+
expect($stderr.string).to match /\w+/
|
833
848
|
end
|
834
849
|
|
835
850
|
describe "with require_note config option set" do
|
@@ -841,21 +856,21 @@ END:VCALENDAR
|
|
841
856
|
it "should prompt for a note if one isn't passed" do
|
842
857
|
$stdin.string = "an interactive note\n"
|
843
858
|
invoke "in"
|
844
|
-
$stderr.string.
|
845
|
-
Timetrap::Timer.active_entry.note.
|
859
|
+
expect($stderr.string).to include('enter a note')
|
860
|
+
expect(Timetrap::Timer.active_entry.note).to eq "an interactive note"
|
846
861
|
end
|
847
862
|
|
848
863
|
it "should not prompt for a note if one is passed" do
|
849
864
|
$stdin.string = "an interactive note\n"
|
850
865
|
invoke "in a normal note"
|
851
|
-
Timetrap::Timer.active_entry.note.
|
866
|
+
expect(Timetrap::Timer.active_entry.note).to eq "a normal note"
|
852
867
|
end
|
853
868
|
|
854
869
|
it "should not stop the running entry or prompt" do
|
855
870
|
invoke "in a normal note"
|
856
871
|
$stdin.string = "an interactive note\n"
|
857
872
|
invoke "in"
|
858
|
-
Timetrap::Timer.active_entry.note.
|
873
|
+
expect(Timetrap::Timer.active_entry.note).to eq "a normal note"
|
859
874
|
end
|
860
875
|
end
|
861
876
|
|
@@ -866,22 +881,22 @@ END:VCALENDAR
|
|
866
881
|
end
|
867
882
|
|
868
883
|
it "should open an editor for writing the note" do |example|
|
869
|
-
Timetrap::CLI.
|
884
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
870
885
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
871
886
|
File.write(path[:path], "written in editor")
|
872
887
|
end
|
873
888
|
invoke "in"
|
874
|
-
$stderr.string.
|
875
|
-
Timetrap::Timer.active_entry.note.
|
889
|
+
expect($stderr.string).not_to include('enter a note')
|
890
|
+
expect(Timetrap::Timer.active_entry.note).to eq "written in editor"
|
876
891
|
end
|
877
892
|
|
878
893
|
it "should preserve linebreaks from editor" do |example|
|
879
|
-
Timetrap::CLI.
|
894
|
+
allow(Timetrap::CLI).to receive(:system) do |editor_command|
|
880
895
|
path = editor_command.match(/#{note_editor_command} (?<path>.*)/)
|
881
896
|
File.write(path[:path], "line1\nline2")
|
882
897
|
end
|
883
898
|
invoke "in"
|
884
|
-
Timetrap::Timer.active_entry.note.
|
899
|
+
expect(Timetrap::Timer.active_entry.note).to eq "line1\nline2"
|
885
900
|
end
|
886
901
|
end
|
887
902
|
end
|
@@ -892,9 +907,9 @@ END:VCALENDAR
|
|
892
907
|
end
|
893
908
|
|
894
909
|
it "should check in normally if nothing else is running" do
|
895
|
-
Timetrap::Timer.
|
910
|
+
expect(Timetrap::Timer).not_to be_running #precondition
|
896
911
|
invoke 'in'
|
897
|
-
Timetrap::Timer.
|
912
|
+
expect(Timetrap::Timer).to be_running
|
898
913
|
end
|
899
914
|
|
900
915
|
describe "with a running entry on current sheet" do
|
@@ -906,12 +921,12 @@ END:VCALENDAR
|
|
906
921
|
it "should check out and back in" do
|
907
922
|
entry = Timetrap::Timer.active_entry('sheet1')
|
908
923
|
invoke 'in second task'
|
909
|
-
Timetrap::Timer.active_entry('sheet1').note.
|
924
|
+
expect(Timetrap::Timer.active_entry('sheet1').note).to eq 'second task'
|
910
925
|
end
|
911
926
|
|
912
927
|
it "should tell me what it's doing" do
|
913
928
|
invoke 'in second task'
|
914
|
-
$stderr.string.
|
929
|
+
expect($stderr.string).to include "Checked out"
|
915
930
|
end
|
916
931
|
end
|
917
932
|
|
@@ -923,25 +938,25 @@ END:VCALENDAR
|
|
923
938
|
end
|
924
939
|
|
925
940
|
it "should check out of the running entry" do
|
926
|
-
Timetrap::Timer.active_entry('sheet1').
|
941
|
+
expect(Timetrap::Timer.active_entry('sheet1')).to be_a(Timetrap::Entry)
|
927
942
|
invoke 'in second task'
|
928
|
-
Timetrap::Timer.active_entry('sheet1').
|
943
|
+
expect(Timetrap::Timer.active_entry('sheet1')).to be nil
|
929
944
|
end
|
930
945
|
|
931
946
|
it "should check out of the running entry at another time" do
|
932
947
|
now = Time.at(Time.now - 5 * 60) # 5 minutes ago
|
933
948
|
entry = Timetrap::Timer.active_entry('sheet1')
|
934
|
-
entry.
|
949
|
+
expect(entry).to be_a(Timetrap::Entry)
|
935
950
|
invoke "in -a '#{now}' second task"
|
936
|
-
entry.reload.end.to_s.
|
951
|
+
expect(entry.reload.end.to_s).to eq now.to_s
|
937
952
|
end
|
938
953
|
|
939
954
|
it "should check out of the running entry without having to start a new entry" do
|
940
955
|
entry = Timetrap::Timer.active_entry('sheet1')
|
941
|
-
entry.
|
942
|
-
entry.end.
|
956
|
+
expect(entry).to be_a(Timetrap::Entry)
|
957
|
+
expect(entry.end).to be_nil
|
943
958
|
invoke "out"
|
944
|
-
entry.reload.end.
|
959
|
+
expect(entry.reload.end).not_to be_nil
|
945
960
|
end
|
946
961
|
end
|
947
962
|
end
|
@@ -956,8 +971,8 @@ END:VCALENDAR
|
|
956
971
|
)
|
957
972
|
create_entry
|
958
973
|
invoke 'today'
|
959
|
-
$stdout.string.
|
960
|
-
$stdout.string.
|
974
|
+
expect($stdout.string).to include Time.now.strftime('%a %b %d, %Y')
|
975
|
+
expect($stdout.string).not_to include yesterday.strftime('%a %b %d, %Y')
|
961
976
|
end
|
962
977
|
end
|
963
978
|
|
@@ -970,8 +985,8 @@ END:VCALENDAR
|
|
970
985
|
)
|
971
986
|
create_entry
|
972
987
|
invoke 'yesterday'
|
973
|
-
$stdout.string.
|
974
|
-
$stdout.string.
|
988
|
+
expect($stdout.string).to include yesterday.strftime('%a %b %d, %Y')
|
989
|
+
expect($stdout.string).not_to include Time.now.strftime('%a %b %d, %Y')
|
975
990
|
end
|
976
991
|
end
|
977
992
|
|
@@ -983,8 +998,8 @@ END:VCALENDAR
|
|
983
998
|
)
|
984
999
|
create_entry
|
985
1000
|
invoke 'week'
|
986
|
-
$stdout.string.
|
987
|
-
$stdout.string.
|
1001
|
+
expect($stdout.string).to include Time.now.strftime('%a %b %d, %Y')
|
1002
|
+
expect($stdout.string).not_to include 'Feb 01, 2012'
|
988
1003
|
end
|
989
1004
|
|
990
1005
|
describe "with week_start config option set" do
|
@@ -995,14 +1010,14 @@ END:VCALENDAR
|
|
995
1010
|
|
996
1011
|
#https://github.com/samg/timetrap/issues/161
|
997
1012
|
it "should work at the end of the month" do
|
998
|
-
Date.
|
1013
|
+
expect(Date).to receive(:today).and_return(Date.new(2017 , 7, 30))
|
999
1014
|
|
1000
1015
|
create_entry(
|
1001
1016
|
:start => Time.local(2017, 7, 29, 1, 2, 3),
|
1002
1017
|
:end => Time.local(2017, 7, 29, 2, 2, 3)
|
1003
1018
|
)
|
1004
1019
|
invoke "week"
|
1005
|
-
$stdout.string.
|
1020
|
+
expect($stdout.string).to include 'Jul 29, 2017'
|
1006
1021
|
|
1007
1022
|
end
|
1008
1023
|
|
@@ -1020,12 +1035,12 @@ END:VCALENDAR
|
|
1020
1035
|
:end => Time.local(2012, 2, 9, 2, 2, 3)
|
1021
1036
|
)
|
1022
1037
|
|
1023
|
-
Date.
|
1038
|
+
expect(Date).to receive(:today).and_return(Date.new(2012, 2, 9))
|
1024
1039
|
invoke 'week'
|
1025
1040
|
|
1026
|
-
$stdout.string.
|
1027
|
-
$stdout.string.
|
1028
|
-
$stdout.string.
|
1041
|
+
expect($stdout.string).to include 'Feb 08, 2012'
|
1042
|
+
expect($stdout.string).to include 'Feb 09, 2012'
|
1043
|
+
expect($stdout.string).not_to include 'Feb 05, 2012'
|
1029
1044
|
end
|
1030
1045
|
|
1031
1046
|
it "should only show entries from today if today is start of week" do
|
@@ -1042,12 +1057,12 @@ END:VCALENDAR
|
|
1042
1057
|
:end => Time.local(2012, 2, 7, 2, 2, 3)
|
1043
1058
|
)
|
1044
1059
|
|
1045
|
-
Date.
|
1060
|
+
expect(Date).to receive(:today).and_return(Date.new(2012, 2, 7))
|
1046
1061
|
invoke 'week'
|
1047
1062
|
|
1048
|
-
$stdout.string.
|
1049
|
-
$stdout.string.
|
1050
|
-
$stdout.string.
|
1063
|
+
expect($stdout.string).to include 'Feb 07, 2012'
|
1064
|
+
expect($stdout.string).not_to include 'Jan 31, 2012'
|
1065
|
+
expect($stdout.string).not_to include 'Feb 05, 2012'
|
1051
1066
|
end
|
1052
1067
|
|
1053
1068
|
it "should not show entries 7 days past start of week" do
|
@@ -1064,12 +1079,12 @@ END:VCALENDAR
|
|
1064
1079
|
:end => Time.local(2012, 2, 16, 2, 2, 3)
|
1065
1080
|
)
|
1066
1081
|
|
1067
|
-
Date.
|
1082
|
+
expect(Date).to receive(:today).and_return(Date.new(2012, 2, 7))
|
1068
1083
|
invoke 'week'
|
1069
1084
|
|
1070
|
-
$stdout.string.
|
1071
|
-
$stdout.string.
|
1072
|
-
$stdout.string.
|
1085
|
+
expect($stdout.string).to include 'Feb 09, 2012'
|
1086
|
+
expect($stdout.string).not_to include 'Feb 14, 2012'
|
1087
|
+
expect($stdout.string).not_to include 'Feb 16, 2012'
|
1073
1088
|
end
|
1074
1089
|
end
|
1075
1090
|
end
|
@@ -1089,13 +1104,13 @@ END:VCALENDAR
|
|
1089
1104
|
:end => Time.local(2012, 1, 5, 2, 2, 3)
|
1090
1105
|
)
|
1091
1106
|
|
1092
|
-
Date.
|
1107
|
+
expect(Date).to receive(:today).and_return(Date.new(2012, 2, 5))
|
1093
1108
|
invoke "month"
|
1094
1109
|
|
1095
1110
|
|
1096
|
-
$stdout.string.
|
1097
|
-
$stdout.string.
|
1098
|
-
$stdout.string.
|
1111
|
+
expect($stdout.string).to include 'Feb 05, 2012'
|
1112
|
+
expect($stdout.string).to include 'Feb 06, 2012'
|
1113
|
+
expect($stdout.string).not_to include 'Jan'
|
1099
1114
|
end
|
1100
1115
|
|
1101
1116
|
it "should work in December" do
|
@@ -1104,10 +1119,10 @@ END:VCALENDAR
|
|
1104
1119
|
:end => Time.local(2012, 12, 5, 2, 2, 3)
|
1105
1120
|
)
|
1106
1121
|
|
1107
|
-
Date.
|
1122
|
+
expect(Date).to receive(:today).and_return(Date.new(2012, 12, 5))
|
1108
1123
|
invoke "month"
|
1109
1124
|
|
1110
|
-
$stdout.string.
|
1125
|
+
expect($stdout.string).to include 'Wed Dec 05, 2012 01:02:03 - 02:02:03'
|
1111
1126
|
end
|
1112
1127
|
end
|
1113
1128
|
|
@@ -1123,41 +1138,41 @@ END:VCALENDAR
|
|
1123
1138
|
it "should delete a timesheet" do
|
1124
1139
|
create_entry
|
1125
1140
|
entry = create_entry
|
1126
|
-
lambda do
|
1141
|
+
expect(lambda do
|
1127
1142
|
$stdin.string = "yes\n"
|
1128
1143
|
invoke "kill #{entry.sheet}"
|
1129
|
-
|
1144
|
+
end).to change(Timetrap::Entry, :count).by(-2)
|
1130
1145
|
end
|
1131
1146
|
|
1132
1147
|
it "should delete an entry" do
|
1133
1148
|
create_entry
|
1134
1149
|
entry = create_entry
|
1135
|
-
lambda do
|
1150
|
+
expect(lambda do
|
1136
1151
|
$stdin.string = "yes\n"
|
1137
1152
|
invoke "kill --id #{entry.id}"
|
1138
|
-
|
1153
|
+
end).to change(Timetrap::Entry, :count).by(-1)
|
1139
1154
|
end
|
1140
1155
|
|
1141
1156
|
it "should not prompt the user if the --yes flag is passed" do
|
1142
1157
|
create_entry
|
1143
1158
|
entry = create_entry
|
1144
|
-
lambda do
|
1159
|
+
expect(lambda do
|
1145
1160
|
invoke "kill --id #{entry.id} --yes"
|
1146
|
-
|
1161
|
+
end).to change(Timetrap::Entry, :count).by(-1)
|
1147
1162
|
end
|
1148
1163
|
|
1149
1164
|
describe "with a numeric sheet name" do
|
1150
1165
|
before do
|
1151
1166
|
now = local_time("2008-10-05 18:00:00")
|
1152
|
-
Time.
|
1167
|
+
allow(Time).to receive(:now).and_return now
|
1153
1168
|
create_entry( :sheet => 1234, :start => local_time_cli('2008-10-03 12:00:00'),
|
1154
1169
|
:end => local_time_cli('2008-10-03 14:00:00'))
|
1155
1170
|
end
|
1156
1171
|
|
1157
1172
|
it "should kill the sheet" do
|
1158
|
-
lambda do
|
1173
|
+
expect(lambda do
|
1159
1174
|
invoke 'kill -y 1234'
|
1160
|
-
|
1175
|
+
end).to change(Timetrap::Entry, :count).by(-1)
|
1161
1176
|
end
|
1162
1177
|
end
|
1163
1178
|
end
|
@@ -1166,21 +1181,21 @@ END:VCALENDAR
|
|
1166
1181
|
describe "with no sheets defined" do
|
1167
1182
|
it "should list the default sheet" do
|
1168
1183
|
invoke 'list'
|
1169
|
-
$stdout.string.chomp.
|
1184
|
+
expect($stdout.string.chomp).to eq " Timesheet Running Today Total Time\n*default 0:00:00 0:00:00 0:00:00"
|
1170
1185
|
end
|
1171
1186
|
end
|
1172
1187
|
|
1173
1188
|
describe "with a numeric sheet name" do
|
1174
1189
|
before do
|
1175
1190
|
now = local_time("2008-10-05 18:00:00")
|
1176
|
-
Time.
|
1191
|
+
allow(Time).to receive(:now).and_return now
|
1177
1192
|
create_entry( :sheet => '1234', :start => local_time_cli('2008-10-03 12:00:00'),
|
1178
1193
|
:end => local_time_cli('2008-10-03 14:00:00'))
|
1179
1194
|
end
|
1180
1195
|
|
1181
1196
|
it "should list the sheet" do
|
1182
1197
|
invoke 'list'
|
1183
|
-
$stdout.string.
|
1198
|
+
expect($stdout.string).to eq " Timesheet Running Today Total Time\n 1234 0:00:00 0:00:00 2:00:00\n*default 0:00:00 0:00:00 0:00:00\n"
|
1184
1199
|
end
|
1185
1200
|
end
|
1186
1201
|
|
@@ -1191,14 +1206,14 @@ END:VCALENDAR
|
|
1191
1206
|
|
1192
1207
|
it "should list the sheet" do
|
1193
1208
|
invoke 'list'
|
1194
|
-
$stdout.string.
|
1209
|
+
expect($stdout.string).to eq " Timesheet Running Today Total Time\n*1234 0:00:00 0:00:00 0:00:00\n"
|
1195
1210
|
end
|
1196
1211
|
end
|
1197
1212
|
|
1198
1213
|
describe "with sheets defined" do
|
1199
1214
|
before :each do
|
1200
1215
|
now = local_time("2008-10-05 18:00:00")
|
1201
|
-
Time.
|
1216
|
+
allow(Time).to receive(:now).and_return now
|
1202
1217
|
create_entry( :sheet => 'A Longly Named Sheet 2', :start => local_time_cli('2008-10-03 12:00:00'),
|
1203
1218
|
:end => local_time_cli('2008-10-03 14:00:00'))
|
1204
1219
|
create_entry( :sheet => 'A Longly Named Sheet 2', :start => local_time_cli('2008-10-03 12:00:00'),
|
@@ -1213,7 +1228,7 @@ END:VCALENDAR
|
|
1213
1228
|
end
|
1214
1229
|
it "should list available timesheets" do
|
1215
1230
|
invoke 'list'
|
1216
|
-
$stdout.string.
|
1231
|
+
expect($stdout.string).to eq <<-OUTPUT
|
1217
1232
|
Timesheet Running Today Total Time
|
1218
1233
|
*A Longly Named Sheet 2 4:00:00 6:00:00 10:00:00
|
1219
1234
|
Sheet 1 0:00:00 0:00:00 2:00:00
|
@@ -1224,7 +1239,7 @@ END:VCALENDAR
|
|
1224
1239
|
invoke 'sheet Sheet 1'
|
1225
1240
|
$stdout.string = ''
|
1226
1241
|
invoke 'list'
|
1227
|
-
$stdout.string.
|
1242
|
+
expect($stdout.string).to eq <<-OUTPUT
|
1228
1243
|
Timesheet Running Today Total Time
|
1229
1244
|
-A Longly Named Sheet 2 4:00:00 6:00:00 10:00:00
|
1230
1245
|
*Sheet 1 0:00:00 0:00:00 2:00:00
|
@@ -1236,7 +1251,7 @@ END:VCALENDAR
|
|
1236
1251
|
invoke 'sheet Sheet 1'
|
1237
1252
|
$stdout.string = ''
|
1238
1253
|
invoke 'list'
|
1239
|
-
$stdout.string.
|
1254
|
+
expect($stdout.string).to eq <<-OUTPUT
|
1240
1255
|
Timesheet Running Today Total Time
|
1241
1256
|
A Longly Named Sheet 2 4:00:00 6:00:00 10:00:00
|
1242
1257
|
*Sheet 1 0:00:00 0:00:00 2:00:00
|
@@ -1247,7 +1262,7 @@ END:VCALENDAR
|
|
1247
1262
|
invoke 'sheet empty sheet'
|
1248
1263
|
$stdout.string = ''
|
1249
1264
|
invoke 'list'
|
1250
|
-
$stdout.string.
|
1265
|
+
expect($stdout.string).to eq <<-OUTPUT
|
1251
1266
|
Timesheet Running Today Total Time
|
1252
1267
|
-A Longly Named Sheet 2 4:00:00 6:00:00 10:00:00
|
1253
1268
|
*empty sheet 0:00:00 0:00:00 0:00:00
|
@@ -1265,7 +1280,7 @@ END:VCALENDAR
|
|
1265
1280
|
describe "when the current timesheet isn't running" do
|
1266
1281
|
it "should show that it isn't running" do
|
1267
1282
|
invoke 'now'
|
1268
|
-
$stderr.string.
|
1283
|
+
expect($stderr.string).to eq <<-OUTPUT
|
1269
1284
|
*current sheet: not running
|
1270
1285
|
OUTPUT
|
1271
1286
|
end
|
@@ -1277,12 +1292,12 @@ END:VCALENDAR
|
|
1277
1292
|
@entry = Timetrap::Timer.active_entry
|
1278
1293
|
@entry.start = Time.at(0)
|
1279
1294
|
@entry.save
|
1280
|
-
Time.
|
1295
|
+
allow(Time).to receive(:now).and_return Time.at(60)
|
1281
1296
|
end
|
1282
1297
|
|
1283
1298
|
it "should show how long the current item is running for" do
|
1284
1299
|
invoke 'now'
|
1285
|
-
$stdout.string.
|
1300
|
+
expect($stdout.string).to eq <<-OUTPUT
|
1286
1301
|
*current sheet: 0:01:00 (a timesheet that is running)
|
1287
1302
|
OUTPUT
|
1288
1303
|
end
|
@@ -1294,12 +1309,12 @@ END:VCALENDAR
|
|
1294
1309
|
@entry = Timetrap::Timer.active_entry
|
1295
1310
|
@entry.start = Time.at(0)
|
1296
1311
|
@entry.save
|
1297
|
-
Time.
|
1312
|
+
allow(Time).to receive(:now).and_return Time.at(60)
|
1298
1313
|
end
|
1299
1314
|
|
1300
1315
|
it "should show both entries" do
|
1301
1316
|
invoke 'now'
|
1302
|
-
$stdout.string.
|
1317
|
+
expect($stdout.string).to eq <<-OUTPUT
|
1303
1318
|
current sheet: 0:01:00 (a timesheet that is running)
|
1304
1319
|
*another-sheet: 0:01:00 (also running)
|
1305
1320
|
OUTPUT
|
@@ -1313,41 +1328,41 @@ END:VCALENDAR
|
|
1313
1328
|
invoke 'in'
|
1314
1329
|
@active = Timetrap::Timer.active_entry
|
1315
1330
|
@now = Time.now
|
1316
|
-
Time.
|
1331
|
+
allow(Time).to receive(:now).and_return @now
|
1317
1332
|
end
|
1318
1333
|
it "should set the stop for the running entry" do
|
1319
|
-
@active.refresh.end.
|
1334
|
+
expect(@active.refresh.end).to eq nil
|
1320
1335
|
invoke 'out'
|
1321
|
-
@active.refresh.end.to_i.
|
1336
|
+
expect(@active.refresh.end.to_i).to eq @now.to_i
|
1322
1337
|
end
|
1323
1338
|
|
1324
1339
|
it "should not do anything if nothing is running" do
|
1325
|
-
lambda do
|
1340
|
+
expect(lambda do
|
1326
1341
|
invoke 'out'
|
1327
1342
|
invoke 'out'
|
1328
|
-
|
1343
|
+
end).not_to raise_error
|
1329
1344
|
end
|
1330
1345
|
|
1331
1346
|
it "should allow the sheet to be stopped at a certain time" do
|
1332
1347
|
invoke 'out --at "10am 2008-10-03"'
|
1333
|
-
@active.refresh.end.
|
1348
|
+
expect(@active.refresh.end).to eq Time.parse('2008-10-03 10:00')
|
1334
1349
|
end
|
1335
1350
|
|
1336
1351
|
it "should allow you to check out of a non active sheet" do
|
1337
1352
|
invoke 'sheet SomeOtherSheet'
|
1338
1353
|
invoke 'in'
|
1339
1354
|
@new_active = Timetrap::Timer.active_entry
|
1340
|
-
@active.
|
1355
|
+
expect(@active).not_to eq @new_active
|
1341
1356
|
invoke %'out #{@active.sheet} --at "10am 2008-10-03"'
|
1342
|
-
@active.refresh.end.
|
1343
|
-
@new_active.refresh.end.
|
1357
|
+
expect(@active.refresh.end).to eq Time.parse('2008-10-03 10:00')
|
1358
|
+
expect(@new_active.refresh.end).to be_nil
|
1344
1359
|
end
|
1345
1360
|
end
|
1346
1361
|
|
1347
1362
|
describe "resume" do
|
1348
1363
|
before :each do
|
1349
1364
|
@time = Time.now
|
1350
|
-
Time.
|
1365
|
+
allow(Time).to receive(:now).and_return @time
|
1351
1366
|
|
1352
1367
|
invoke 'in A previous task that isnt last'
|
1353
1368
|
@previous = Timetrap::Timer.active_entry
|
@@ -1357,15 +1372,15 @@ END:VCALENDAR
|
|
1357
1372
|
@last_active = Timetrap::Timer.active_entry
|
1358
1373
|
invoke 'out'
|
1359
1374
|
|
1360
|
-
Timetrap::Timer.active_entry.
|
1361
|
-
@last_active.
|
1375
|
+
expect(Timetrap::Timer.active_entry).to be_nil
|
1376
|
+
expect(@last_active).not_to be_nil
|
1362
1377
|
end
|
1363
1378
|
|
1364
1379
|
it "should allow to resume the last active entry" do
|
1365
1380
|
invoke 'resume'
|
1366
1381
|
|
1367
|
-
Timetrap::Timer.active_entry.note.
|
1368
|
-
Timetrap::Timer.active_entry.start.to_s.
|
1382
|
+
expect(Timetrap::Timer.active_entry.note).to eq(@last_active.note)
|
1383
|
+
expect(Timetrap::Timer.active_entry.start.to_s).to eq @time.to_s
|
1369
1384
|
end
|
1370
1385
|
|
1371
1386
|
it "should allow to resume the last entry from the current sheet" do
|
@@ -1375,28 +1390,28 @@ END:VCALENDAR
|
|
1375
1390
|
invoke 'sheet -'
|
1376
1391
|
invoke 'resume'
|
1377
1392
|
|
1378
|
-
Timetrap::Timer.active_entry.note.
|
1379
|
-
Timetrap::Timer.active_entry.start.to_s.
|
1393
|
+
expect(Timetrap::Timer.active_entry.note).to eq(@last_active.note)
|
1394
|
+
expect(Timetrap::Timer.active_entry.start.to_s).to eq @time.to_s
|
1380
1395
|
end
|
1381
1396
|
|
1382
1397
|
it "should allow to resume a specific entry" do
|
1383
1398
|
invoke "resume --id #{@previous.id}"
|
1384
1399
|
|
1385
|
-
Timetrap::Timer.active_entry.note.
|
1386
|
-
Timetrap::Timer.active_entry.start.to_s.
|
1400
|
+
expect(Timetrap::Timer.active_entry.note).to eq(@previous.note)
|
1401
|
+
expect(Timetrap::Timer.active_entry.start.to_s).to eq @time.to_s
|
1387
1402
|
end
|
1388
1403
|
|
1389
1404
|
it "should allow to resume a specific entry with a given time" do
|
1390
1405
|
invoke "resume --id #{@previous.id} --at \"10am 2008-10-03\""
|
1391
1406
|
|
1392
|
-
Timetrap::Timer.active_entry.note.
|
1393
|
-
Timetrap::Timer.active_entry.start.
|
1407
|
+
expect(Timetrap::Timer.active_entry.note).to eq(@previous.note)
|
1408
|
+
expect(Timetrap::Timer.active_entry.start).to eql(Time.parse('2008-10-03 10:00'))
|
1394
1409
|
end
|
1395
1410
|
|
1396
1411
|
it "should allow to resume the activity with a given time" do
|
1397
1412
|
invoke 'resume --at "10am 2008-10-03"'
|
1398
1413
|
|
1399
|
-
Timetrap::Timer.active_entry.start.
|
1414
|
+
expect(Timetrap::Timer.active_entry.start).to eql(Time.parse('2008-10-03 10:00'))
|
1400
1415
|
end
|
1401
1416
|
|
1402
1417
|
describe "no existing entries" do
|
@@ -1405,8 +1420,8 @@ END:VCALENDAR
|
|
1405
1420
|
e.destroy
|
1406
1421
|
end
|
1407
1422
|
|
1408
|
-
Timetrap::Timer.entries(Timetrap::Timer.current_sheet).
|
1409
|
-
Timetrap::Timer.active_entry.
|
1423
|
+
expect(Timetrap::Timer.entries(Timetrap::Timer.current_sheet)).to be_empty
|
1424
|
+
expect(Timetrap::Timer.active_entry).to be_nil
|
1410
1425
|
end
|
1411
1426
|
|
1412
1427
|
end
|
@@ -1415,15 +1430,15 @@ END:VCALENDAR
|
|
1415
1430
|
before(:each) do
|
1416
1431
|
$stdin.string = "yes\n"
|
1417
1432
|
invoke "archive"
|
1418
|
-
Timetrap::Timer.entries(Timetrap::Timer.current_sheet).
|
1419
|
-
Timetrap::Timer.active_entry.
|
1433
|
+
expect(Timetrap::Timer.entries(Timetrap::Timer.current_sheet)).to be_empty
|
1434
|
+
expect(Timetrap::Timer.active_entry).to be_nil
|
1420
1435
|
end
|
1421
1436
|
|
1422
1437
|
it "retrieves the note of the most recent archived entry" do
|
1423
1438
|
invoke "resume"
|
1424
|
-
Timetrap::Timer.active_entry.
|
1425
|
-
Timetrap::Timer.active_entry.note.
|
1426
|
-
Timetrap::Timer.active_entry.start.to_s.
|
1439
|
+
expect(Timetrap::Timer.active_entry).not_to be_nil
|
1440
|
+
expect(Timetrap::Timer.active_entry.note).to eq @last_active.note
|
1441
|
+
expect(Timetrap::Timer.active_entry.start.to_s).to eq @time.to_s
|
1427
1442
|
end
|
1428
1443
|
end
|
1429
1444
|
|
@@ -1433,9 +1448,9 @@ END:VCALENDAR
|
|
1433
1448
|
end
|
1434
1449
|
|
1435
1450
|
it "should check in normally if nothing else is running" do
|
1436
|
-
Timetrap::Timer.
|
1451
|
+
expect(Timetrap::Timer).not_to be_running #precondition
|
1437
1452
|
invoke 'resume'
|
1438
|
-
Timetrap::Timer.
|
1453
|
+
expect(Timetrap::Timer).to be_running
|
1439
1454
|
end
|
1440
1455
|
|
1441
1456
|
describe "with a running entry on current sheet" do
|
@@ -1447,7 +1462,7 @@ END:VCALENDAR
|
|
1447
1462
|
it "should check out and back in" do
|
1448
1463
|
entry = Timetrap::Timer.active_entry('sheet1')
|
1449
1464
|
invoke 'resume second task'
|
1450
|
-
Timetrap::Timer.active_entry('sheet1').id.
|
1465
|
+
expect(Timetrap::Timer.active_entry('sheet1').id).not_to eq entry.id
|
1451
1466
|
end
|
1452
1467
|
end
|
1453
1468
|
|
@@ -1463,17 +1478,17 @@ END:VCALENDAR
|
|
1463
1478
|
end
|
1464
1479
|
|
1465
1480
|
it "should check out of the running entry" do
|
1466
|
-
Timetrap::Timer.active_entry('sheet1').
|
1481
|
+
expect(Timetrap::Timer.active_entry('sheet1')).to be_a(Timetrap::Entry)
|
1467
1482
|
invoke 'resume'
|
1468
|
-
Timetrap::Timer.active_entry('sheet1').
|
1483
|
+
expect(Timetrap::Timer.active_entry('sheet1')).to be nil
|
1469
1484
|
end
|
1470
1485
|
|
1471
1486
|
it "should check out of the running entry at another time" do
|
1472
1487
|
now = Time.at(Time.now - 5 * 60) # 5 minutes ago
|
1473
1488
|
entry = Timetrap::Timer.active_entry('sheet1')
|
1474
|
-
entry.
|
1489
|
+
expect(entry).to be_a(Timetrap::Entry)
|
1475
1490
|
invoke "resume -a '#{now}'"
|
1476
|
-
entry.reload.end.to_s.
|
1491
|
+
expect(entry.reload.end.to_s).to eq now.to_s
|
1477
1492
|
end
|
1478
1493
|
end
|
1479
1494
|
end
|
@@ -1482,36 +1497,50 @@ END:VCALENDAR
|
|
1482
1497
|
describe "sheet" do
|
1483
1498
|
it "should switch to a new timesheet" do
|
1484
1499
|
invoke 'sheet sheet 1'
|
1485
|
-
Timetrap::Timer.current_sheet.
|
1500
|
+
expect(Timetrap::Timer.current_sheet).to eq 'sheet 1'
|
1486
1501
|
invoke 'sheet sheet 2'
|
1487
|
-
Timetrap::Timer.current_sheet.
|
1502
|
+
expect(Timetrap::Timer.current_sheet).to eq 'sheet 2'
|
1488
1503
|
end
|
1489
1504
|
|
1490
1505
|
it "should not switch to an blank timesheet" do
|
1491
1506
|
invoke 'sheet sheet 1'
|
1492
1507
|
invoke 'sheet'
|
1493
|
-
Timetrap::Timer.current_sheet.
|
1508
|
+
expect(Timetrap::Timer.current_sheet).to eq 'sheet 1'
|
1494
1509
|
end
|
1495
1510
|
|
1496
1511
|
it "should list timesheets when there are no arguments" do
|
1497
1512
|
invoke 'sheet sheet 1'
|
1498
1513
|
invoke 'sheet'
|
1499
|
-
$stdout.string.
|
1514
|
+
expect($stdout.string).to eq " Timesheet Running Today Total Time\n*sheet 1 0:00:00 0:00:00 0:00:00\n"
|
1515
|
+
end
|
1516
|
+
|
1517
|
+
it "should note if the user is already on that sheet" do
|
1518
|
+
create_entry(sheet: "sheet 1")
|
1519
|
+
invoke 'sheet sheet 1'
|
1520
|
+
invoke 'sheet sheet 1'
|
1521
|
+
expect($stderr.string).to eq "Switching to sheet \"sheet 1\"\nAlready on sheet \"sheet 1\"\n"
|
1522
|
+
end
|
1523
|
+
|
1524
|
+
it "should indicate when switching to a new sheet" do
|
1525
|
+
create_entry(sheet: "foo")
|
1526
|
+
invoke 'sheet foo'
|
1527
|
+
invoke 'sheet bar'
|
1528
|
+
expect($stderr.string).to eq "Switching to sheet \"foo\"\nSwitching to sheet \"bar\" (new sheet)\n"
|
1500
1529
|
end
|
1501
1530
|
|
1502
1531
|
describe "using - to switch to the last sheet" do
|
1503
1532
|
it "should warn if there isn't a sheet set" do
|
1504
|
-
lambda do
|
1533
|
+
expect(lambda do
|
1505
1534
|
invoke 'sheet -'
|
1506
|
-
|
1507
|
-
|
1535
|
+
end).not_to change(Timetrap::Timer, :current_sheet)
|
1536
|
+
expect($stderr.string).to include 'LAST_SHEET is not set'
|
1508
1537
|
end
|
1509
1538
|
|
1510
1539
|
it "should switch to the last active sheet" do
|
1511
1540
|
invoke 'sheet second'
|
1512
|
-
lambda do
|
1541
|
+
expect(lambda do
|
1513
1542
|
invoke 'sheet -'
|
1514
|
-
|
1543
|
+
end).to change(Timetrap::Timer, :current_sheet).
|
1515
1544
|
from('second').to('default')
|
1516
1545
|
end
|
1517
1546
|
|
@@ -1520,9 +1549,9 @@ END:VCALENDAR
|
|
1520
1549
|
invoke 'sheet second'
|
1521
1550
|
5.times do
|
1522
1551
|
invoke 's -'
|
1523
|
-
Timetrap::Timer.current_sheet.
|
1552
|
+
expect(Timetrap::Timer.current_sheet).to eq 'first'
|
1524
1553
|
invoke 's -'
|
1525
|
-
Timetrap::Timer.current_sheet.
|
1554
|
+
expect(Timetrap::Timer.current_sheet).to eq 'second'
|
1526
1555
|
end
|
1527
1556
|
end
|
1528
1557
|
end
|
@@ -1535,7 +1564,7 @@ END:VCALENDAR
|
|
1535
1564
|
rescue SystemExit #Getopt::Declare calls exit after --version is invoked
|
1536
1565
|
end
|
1537
1566
|
|
1538
|
-
$stdout.string.
|
1567
|
+
expect($stdout.string).to include(::Timetrap::VERSION)
|
1539
1568
|
end
|
1540
1569
|
end
|
1541
1570
|
end
|
@@ -1544,7 +1573,7 @@ END:VCALENDAR
|
|
1544
1573
|
describe "entries" do
|
1545
1574
|
it "should give the entires for a sheet" do
|
1546
1575
|
e = create_entry :sheet => 'sheet'
|
1547
|
-
Timetrap::Timer.entries('sheet').all.
|
1576
|
+
expect(Timetrap::Timer.entries('sheet').all).to include(e)
|
1548
1577
|
end
|
1549
1578
|
|
1550
1579
|
end
|
@@ -1553,26 +1582,26 @@ END:VCALENDAR
|
|
1553
1582
|
it "should start an new entry" do
|
1554
1583
|
@time = Time.now
|
1555
1584
|
Timetrap::Timer.current_sheet = 'sheet1'
|
1556
|
-
lambda do
|
1585
|
+
expect(lambda do
|
1557
1586
|
Timetrap::Timer.start 'some work', @time
|
1558
|
-
|
1559
|
-
Timetrap::Entry.order(:id).last.sheet.
|
1560
|
-
Timetrap::Entry.order(:id).last.note.
|
1561
|
-
Timetrap::Entry.order(:id).last.start.to_i.
|
1562
|
-
Timetrap::Entry.order(:id).last.end.
|
1587
|
+
end).to change(Timetrap::Entry, :count).by(1)
|
1588
|
+
expect(Timetrap::Entry.order(:id).last.sheet).to eq 'sheet1'
|
1589
|
+
expect(Timetrap::Entry.order(:id).last.note).to eq 'some work'
|
1590
|
+
expect(Timetrap::Entry.order(:id).last.start.to_i).to eq @time.to_i
|
1591
|
+
expect(Timetrap::Entry.order(:id).last.end).to be_nil
|
1563
1592
|
end
|
1564
1593
|
|
1565
1594
|
it "should be running if it is started" do
|
1566
|
-
Timetrap::Timer.
|
1595
|
+
expect(Timetrap::Timer).not_to be_running
|
1567
1596
|
Timetrap::Timer.start 'some work', @time
|
1568
|
-
Timetrap::Timer.
|
1597
|
+
expect(Timetrap::Timer).to be_running
|
1569
1598
|
end
|
1570
1599
|
|
1571
1600
|
it "should raise an error if it is already running" do
|
1572
|
-
lambda do
|
1601
|
+
expect(lambda do
|
1573
1602
|
Timetrap::Timer.start 'some work', @time
|
1574
1603
|
Timetrap::Timer.start 'some work', @time
|
1575
|
-
|
1604
|
+
end).to raise_error(Timetrap::Timer::AlreadyRunning)
|
1576
1605
|
end
|
1577
1606
|
end
|
1578
1607
|
|
@@ -1581,16 +1610,16 @@ END:VCALENDAR
|
|
1581
1610
|
@time = Time.now
|
1582
1611
|
Timetrap::Timer.start 'some work', @time
|
1583
1612
|
entry = Timetrap::Timer.active_entry
|
1584
|
-
entry.end.
|
1613
|
+
expect(entry.end).to be_nil
|
1585
1614
|
Timetrap::Timer.stop Timetrap::Timer.current_sheet, @time
|
1586
|
-
entry.refresh.end.to_i.
|
1615
|
+
expect(entry.refresh.end.to_i).to eq @time.to_i
|
1587
1616
|
end
|
1588
1617
|
|
1589
1618
|
it "should not be running if it is stopped" do
|
1590
|
-
Timetrap::Timer.
|
1619
|
+
expect(Timetrap::Timer).not_to be_running
|
1591
1620
|
Timetrap::Timer.start 'some work', @time
|
1592
1621
|
Timetrap::Timer.stop Timetrap::Timer.current_sheet
|
1593
|
-
Timetrap::Timer.
|
1622
|
+
expect(Timetrap::Timer).not_to be_running
|
1594
1623
|
end
|
1595
1624
|
|
1596
1625
|
it "should not stop it twice" do
|
@@ -1599,14 +1628,14 @@ END:VCALENDAR
|
|
1599
1628
|
Timetrap::Timer.stop Timetrap::Timer.current_sheet
|
1600
1629
|
time = e.refresh.end
|
1601
1630
|
Timetrap::Timer.stop Timetrap::Timer.current_sheet
|
1602
|
-
time.to_i.
|
1631
|
+
expect(time.to_i).to eq e.refresh.end.to_i
|
1603
1632
|
end
|
1604
1633
|
|
1605
1634
|
it "should track the last entry that was checked out of" do
|
1606
1635
|
Timetrap::Timer.start 'some work'
|
1607
1636
|
e = Timetrap::Timer.active_entry
|
1608
1637
|
Timetrap::Timer.stop Timetrap::Timer.current_sheet
|
1609
|
-
Timetrap::Timer.last_checkout.id.
|
1638
|
+
expect(Timetrap::Timer.last_checkout.id).to eq e.id
|
1610
1639
|
end
|
1611
1640
|
|
1612
1641
|
end
|
@@ -1617,18 +1646,17 @@ END:VCALENDAR
|
|
1617
1646
|
@helper.extend Timetrap::Helpers
|
1618
1647
|
end
|
1619
1648
|
it "should correctly format positive durations" do
|
1620
|
-
@helper.format_duration(1234).
|
1649
|
+
expect(@helper.format_duration(1234)).to eq " 0:20:34"
|
1621
1650
|
end
|
1622
1651
|
|
1623
1652
|
it "should correctly format negative durations" do
|
1624
|
-
@helper.format_duration(-1234).
|
1653
|
+
expect(@helper.format_duration(-1234)).to eq "- 0:20:34"
|
1625
1654
|
end
|
1626
1655
|
end
|
1627
1656
|
|
1628
1657
|
|
1629
1658
|
describe Timetrap::Entry do
|
1630
1659
|
|
1631
|
-
include Timetrap::StubConfig
|
1632
1660
|
describe "with an instance" do
|
1633
1661
|
before do
|
1634
1662
|
@time = Time.now
|
@@ -1643,7 +1671,7 @@ END:VCALENDAR
|
|
1643
1671
|
Timetrap::Entry.create( :sheet => 'SpecSheet',
|
1644
1672
|
:note => 'entry 2', :start => '2008-10-03 16:00:00', :end => '2008-10-03 18:00:00'
|
1645
1673
|
)
|
1646
|
-
Timetrap::Entry.sheets.
|
1674
|
+
expect(Timetrap::Entry.sheets).to eq %w(another SpecSheet).sort
|
1647
1675
|
end
|
1648
1676
|
end
|
1649
1677
|
|
@@ -1651,32 +1679,22 @@ END:VCALENDAR
|
|
1651
1679
|
describe 'attributes' do
|
1652
1680
|
it "should have a note" do
|
1653
1681
|
@entry.note = "world takeover"
|
1654
|
-
@entry.note.
|
1682
|
+
expect(@entry.note).to eq "world takeover"
|
1655
1683
|
end
|
1656
1684
|
|
1657
1685
|
it "should have a start" do
|
1658
1686
|
@entry.start = @time
|
1659
|
-
@entry.start.to_i.
|
1687
|
+
expect(@entry.start.to_i).to eq @time.to_i
|
1660
1688
|
end
|
1661
1689
|
|
1662
1690
|
it "should have a end" do
|
1663
1691
|
@entry.end = @time
|
1664
|
-
@entry.end.to_i.
|
1692
|
+
expect(@entry.end.to_i).to eq @time.to_i
|
1665
1693
|
end
|
1666
1694
|
|
1667
1695
|
it "should have a sheet" do
|
1668
1696
|
@entry.sheet= 'name'
|
1669
|
-
@entry.sheet.
|
1670
|
-
end
|
1671
|
-
|
1672
|
-
def with_rounding_on
|
1673
|
-
old_val = Timetrap::Entry.round
|
1674
|
-
begin
|
1675
|
-
Timetrap::Entry.round = true
|
1676
|
-
block_return_value = yield
|
1677
|
-
ensure
|
1678
|
-
Timetrap::Entry.round = old_val
|
1679
|
-
end
|
1697
|
+
expect(@entry.sheet).to eq 'name'
|
1680
1698
|
end
|
1681
1699
|
|
1682
1700
|
it "should use round start if the global round attribute is set" do
|
@@ -1684,7 +1702,7 @@ END:VCALENDAR
|
|
1684
1702
|
with_stubbed_config('round_in_seconds' => 900) do
|
1685
1703
|
@time = Chronic.parse("12:55")
|
1686
1704
|
@entry.start = @time
|
1687
|
-
@entry.start.
|
1705
|
+
expect(@entry.start).to eq Chronic.parse("1")
|
1688
1706
|
end
|
1689
1707
|
end
|
1690
1708
|
end
|
@@ -1694,7 +1712,7 @@ END:VCALENDAR
|
|
1694
1712
|
with_stubbed_config('round_in_seconds' => 900) do
|
1695
1713
|
@time = Chronic.parse("12:50")
|
1696
1714
|
@entry.start = @time
|
1697
|
-
@entry.start.
|
1715
|
+
expect(@entry.start).to eq Chronic.parse("12:45")
|
1698
1716
|
end
|
1699
1717
|
end
|
1700
1718
|
end
|
@@ -1703,27 +1721,27 @@ END:VCALENDAR
|
|
1703
1721
|
with_stubbed_config('round_in_seconds' => 900) do
|
1704
1722
|
@time = Chronic.parse("12:50")
|
1705
1723
|
@entry.start = @time
|
1706
|
-
@entry.rounded_start.
|
1724
|
+
expect(@entry.rounded_start).to eq Chronic.parse("12:45")
|
1707
1725
|
end
|
1708
1726
|
end
|
1709
1727
|
|
1710
1728
|
it "should not round nil times" do
|
1711
1729
|
@entry.start = nil
|
1712
|
-
@entry.rounded_start.
|
1730
|
+
expect(@entry.rounded_start).to be_nil
|
1713
1731
|
end
|
1714
1732
|
end
|
1715
1733
|
|
1716
1734
|
describe "parsing natural language times" do
|
1717
1735
|
it "should set start time using english" do
|
1718
1736
|
@entry.start = "yesterday 10am"
|
1719
|
-
@entry.start.
|
1720
|
-
@entry.start.
|
1737
|
+
expect(@entry.start).not_to be_nil
|
1738
|
+
expect(@entry.start).to eq Chronic.parse("yesterday 10am")
|
1721
1739
|
end
|
1722
1740
|
|
1723
1741
|
it "should set end time using english" do
|
1724
1742
|
@entry.end = "tomorrow 1pm"
|
1725
|
-
@entry.end.
|
1726
|
-
@entry.end.
|
1743
|
+
expect(@entry.end).not_to be_nil
|
1744
|
+
expect(@entry.end).to eq Chronic.parse("tomorrow 1pm")
|
1727
1745
|
end
|
1728
1746
|
end
|
1729
1747
|
|
@@ -1734,21 +1752,21 @@ END:VCALENDAR
|
|
1734
1752
|
|
1735
1753
|
# should be about 55 minutes duration. Allow for second rollover
|
1736
1754
|
# within this test.
|
1737
|
-
(3299..3301).
|
1755
|
+
expect((3299..3301)).to include(@entry.duration)
|
1738
1756
|
end
|
1739
1757
|
|
1740
1758
|
it "should not assume negative durations around 12 hour length" do
|
1741
1759
|
@entry.start= Time.at(Time.now - (15 * 3600)) # 15.hour.ago
|
1742
1760
|
@entry.end = Time.at(Time.now - 300).strftime("%H:%M:%S") # ambiguous 5.minutes.ago
|
1743
1761
|
|
1744
|
-
(53699..53701).
|
1762
|
+
expect((53699..53701)).to include(@entry.duration)
|
1745
1763
|
end
|
1746
1764
|
|
1747
1765
|
it "should assume a start time near the current time" do
|
1748
1766
|
time = Time.at(Time.now - 300)
|
1749
1767
|
@entry.start= time.strftime("%H:%M:%S") # ambiguous 5.minutes.ago
|
1750
1768
|
|
1751
|
-
@entry.start.to_i.
|
1769
|
+
expect(@entry.start.to_i).to eq time.to_i
|
1752
1770
|
end
|
1753
1771
|
end
|
1754
1772
|
end
|
@@ -1759,8 +1777,8 @@ END:VCALENDAR
|
|
1759
1777
|
it 'should include a t bin and an equivalent timetrap bin' do
|
1760
1778
|
timetrap = File.open(File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'timetrap')))
|
1761
1779
|
t = File.open(File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 't')))
|
1762
|
-
t.read.
|
1763
|
-
t.stat.mode.
|
1780
|
+
expect(t.read).to eq timetrap.read
|
1781
|
+
expect(t.stat.mode).to eq timetrap.stat.mode
|
1764
1782
|
end
|
1765
1783
|
end
|
1766
1784
|
|