timesheet 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/Manifest.txt +24 -0
- data/README.rdoc +104 -0
- data/Rakefile +29 -0
- data/bin/timesheet +7 -0
- data/lib/timesheet.rb +82 -0
- data/lib/timesheet/range_extensions.rb +24 -0
- data/lib/timesheet/time_entry.rb +50 -0
- data/lib/timesheet/time_log.rb +71 -0
- data/lib/timesheet/time_report.rb +113 -0
- data/lib/timesheet/timesheet_parser.rb +242 -0
- data/lib/timesheet/trollop.rb +761 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/spec/range_extensions_spec.rb +17 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/time_entry_spec.rb +137 -0
- data/spec/time_log_spec.rb +164 -0
- data/spec/time_report_spec.rb +104 -0
- data/spec/timesheet_parser_spec.rb +235 -0
- data/spec/timesheet_spec.rb +188 -0
- data/tasks/rspec.rake +21 -0
- metadata +274 -0
data/script/console
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# File: script/console
|
3
|
+
irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
4
|
+
|
5
|
+
libs = " -r irb/completion"
|
6
|
+
# Perhaps use a console_lib to store any extra methods I may want available in the cosole
|
7
|
+
# libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
|
8
|
+
libs << " -r #{File.dirname(__FILE__) + '/../lib/timesheet.rb'}"
|
9
|
+
puts "Loading timesheet gem"
|
10
|
+
exec "#{irb} #{libs} --simple-prompt"
|
data/script/destroy
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/destroy'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Destroy.new.run(ARGV)
|
data/script/generate
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'rubigen'
|
6
|
+
rescue LoadError
|
7
|
+
require 'rubygems'
|
8
|
+
require 'rubigen'
|
9
|
+
end
|
10
|
+
require 'rubigen/scripts/generate'
|
11
|
+
|
12
|
+
ARGV.shift if ['--help', '-h'].include?(ARGV[0])
|
13
|
+
RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
|
14
|
+
RubiGen::Scripts::Generate.new.run(ARGV)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe Range do
|
4
|
+
|
5
|
+
it "should detect overlaps" do
|
6
|
+
(1..5).overlap?(4..8).should be_true
|
7
|
+
(1...5).overlap?(5..10).should be_false
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should allow include?" do
|
11
|
+
(1..5).include?(2..3).should be_true
|
12
|
+
(1..5).include?(4..8).should be_false
|
13
|
+
(1..5).include?(3).should be_true
|
14
|
+
(1..5).include?(6).should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
begin
|
2
|
+
require 'spec'
|
3
|
+
rescue LoadError
|
4
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
5
|
+
gem 'rspec'
|
6
|
+
require 'spec'
|
7
|
+
end
|
8
|
+
|
9
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
10
|
+
|
11
|
+
require 'timesheet'
|
12
|
+
|
13
|
+
|
14
|
+
#Spec::Runner.configure do |config|
|
15
|
+
# config.mock_with :mocha
|
16
|
+
#end
|
17
|
+
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe TimeEntry do
|
4
|
+
|
5
|
+
context "Construction" do
|
6
|
+
|
7
|
+
it "should allow initialization of fields" do
|
8
|
+
lambda { TimeEntry.new("Project", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0)) }.should_not raise_error()
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should raise ArgumentError if end time is before start time" do
|
12
|
+
lambda { TimeEntry.new("Project", Time.local(2009, 12, 1, 17, 0, 0), Time.local(2009, 12, 1, 9, 0, 0)) }.should raise_error(ArgumentError)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
context "Basic Features" do
|
18
|
+
|
19
|
+
before :each do
|
20
|
+
@time_entry = TimeEntry.new("Project", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
it "should know its initial project" do
|
25
|
+
@time_entry.project.should == "Project"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have an know its initial start time" do
|
29
|
+
@time_entry.start_time.should == Time.local(2009, 12, 1, 9, 0, 0)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should know its initial end time" do
|
33
|
+
@time_entry.end_time.should == Time.local(2009, 12, 1, 17, 0, 0)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should have an initial comment of nil" do
|
37
|
+
@time_entry.comment.should == nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should calculate its duration from start and end times" do
|
41
|
+
@time_entry.duration.should == 8.hours
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should remember its assigned project" do
|
45
|
+
@time_entry.project = "Project2"
|
46
|
+
@time_entry.project.should == "Project2"
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should raise an ArgumentError if a start_time is assigned that is after the end_time" do
|
50
|
+
lambda { @time_entry.start_time = Time.local(2009, 12, 1, 18, 0 , 0) }.should raise_error(ArgumentError)
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should raise an ArgumentError if an end_time is assigned that is before the start_time" do
|
54
|
+
lambda { @time_entry.end_time = Time.local(2009, 12, 1, 8, 0 , 0) }.should raise_error(ArgumentError)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should remember its assigned start time" do
|
58
|
+
time = Time.local(2009, 12, 1, 12, 0, 0)
|
59
|
+
@time_entry.start_time = time
|
60
|
+
@time_entry.start_time.should == time
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should remember its assigned end time" do
|
64
|
+
time = Time.local(2009, 12, 1, 12, 0, 0)
|
65
|
+
@time_entry.end_time = time
|
66
|
+
@time_entry.end_time.should == time
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should remember its assigned comment" do
|
70
|
+
@time_entry.comment = "Comment"
|
71
|
+
@time_entry.comment.should == "Comment"
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should not allow assignment to duration" do
|
75
|
+
@time_entry.should_not respond_to :duration=
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
context "comparison and sorting" do
|
81
|
+
before :each do
|
82
|
+
@early_entry = TimeEntry.new("Project", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 12, 0, 0))
|
83
|
+
@late_entry = TimeEntry.new("Project", Time.local(2009, 12, 1, 13, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should be comparable to other time entries" do
|
87
|
+
@early_entry.should respond_to :<=>
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should order before an entry with a later start time" do
|
91
|
+
lambda { @early_entry < @late_entry}.should be_true
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should order after an entry with an earlier start time" do
|
95
|
+
lambda { @late_entry > @early_entry}.should be_true
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
context "Conflict detection" do
|
100
|
+
|
101
|
+
it "these should not conflict" do
|
102
|
+
entry1 = TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
103
|
+
entry2 = TimeEntry.new("Project2", Time.local(2009, 12, 2, 9, 0, 0), Time.local(2009, 12, 2, 17, 0, 0))
|
104
|
+
|
105
|
+
entry1.conflict?(entry2).should be_false
|
106
|
+
entry2.conflict?(entry1).should be_false
|
107
|
+
end
|
108
|
+
|
109
|
+
|
110
|
+
it "should conflict" do
|
111
|
+
entry1 = TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
112
|
+
entry2 = TimeEntry.new("Project2", Time.local(2009, 12, 1, 12, 0, 0), Time.local(2009, 12, 1, 20, 0, 0))
|
113
|
+
|
114
|
+
entry1.conflict?(entry2).should be_true
|
115
|
+
entry2.conflict?(entry1).should be_true
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should conflict" do
|
119
|
+
entry1 = TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
120
|
+
entry2 = TimeEntry.new("Project2", Time.local(2009, 12, 1, 12, 0, 0), Time.local(2009, 12, 1, 14, 0, 0))
|
121
|
+
|
122
|
+
entry1.conflict?(entry2).should be_true
|
123
|
+
entry2.conflict?(entry1).should be_true
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should not conflict if its start time is the same as another entries end time" do
|
127
|
+
entry1 = TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 12, 0, 0))
|
128
|
+
entry2 = TimeEntry.new("Project2", Time.local(2009, 12, 1, 12, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
129
|
+
|
130
|
+
entry1.conflict?(entry2).should be_false
|
131
|
+
entry2.conflict?(entry1).should be_false
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
TEST_FILE = "/var/tmp/timesheet_test.pstore"
|
4
|
+
|
5
|
+
describe TimeLog do
|
6
|
+
|
7
|
+
after :all do
|
8
|
+
File.delete(TEST_FILE) if File.exists?(TEST_FILE)
|
9
|
+
end
|
10
|
+
|
11
|
+
context "adding items" do
|
12
|
+
|
13
|
+
before :all do
|
14
|
+
File.delete(TEST_FILE) if File.exists?(TEST_FILE)
|
15
|
+
@store = YAML::Store.new(TEST_FILE)
|
16
|
+
@time_log = TimeLog.new(@store)
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
it "should have no entries initially" do
|
21
|
+
@time_log.count.should == 0
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow time entries to be added" do
|
25
|
+
t = Time.now
|
26
|
+
entry = TimeEntry.new("Project1", t.hours_ago(2), t)
|
27
|
+
entry.record_number.should == nil
|
28
|
+
@time_log.add entry
|
29
|
+
@time_log.count.should == 1
|
30
|
+
entry.record_number.should == 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context "finding items" do
|
35
|
+
|
36
|
+
before :all do
|
37
|
+
File.delete(TEST_FILE) if File.exists?(TEST_FILE)
|
38
|
+
@store = YAML::Store.new(TEST_FILE)
|
39
|
+
@time_log = TimeLog.new(@store)
|
40
|
+
|
41
|
+
@time_log.add TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
42
|
+
@time_log.add TimeEntry.new("Project2", Time.local(2009, 12, 2, 9, 0, 0), Time.local(2009, 12, 2, 17, 0, 0))
|
43
|
+
@time_log.add TimeEntry.new("Project3", Time.local(2009, 12, 3, 9, 0, 0), Time.local(2009, 12, 3, 17, 0, 0))
|
44
|
+
@time_log.add TimeEntry.new("Project4", Time.local(2009, 12, 4, 9, 0, 0), Time.local(2009, 12, 4, 17, 0, 0))
|
45
|
+
@time_log.add TimeEntry.new("Project5", Time.local(2009, 12, 5, 9, 0, 0), Time.local(2009, 12, 5, 17, 0, 0))
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
it "should raise an error if attempting to find with an unknown index" do
|
50
|
+
lambda{@time_log.find(100)}.should raise_error(ArgumentError)
|
51
|
+
@time_log.count.should == 5
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should not allow finding by record number" do
|
55
|
+
entry = @time_log.find(2)
|
56
|
+
entry.project.should eql("Project2")
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
context "deleting items" do
|
62
|
+
|
63
|
+
before :all do
|
64
|
+
File.delete(TEST_FILE) if File.exists?(TEST_FILE)
|
65
|
+
@store = YAML::Store.new(TEST_FILE)
|
66
|
+
@time_log = TimeLog.new(@store)
|
67
|
+
|
68
|
+
@time_log.add TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
69
|
+
@time_log.add TimeEntry.new("Project2", Time.local(2009, 12, 2, 9, 0, 0), Time.local(2009, 12, 2, 17, 0, 0))
|
70
|
+
@time_log.add TimeEntry.new("Project3", Time.local(2009, 12, 3, 9, 0, 0), Time.local(2009, 12, 3, 17, 0, 0))
|
71
|
+
@time_log.add TimeEntry.new("Project4", Time.local(2009, 12, 4, 9, 0, 0), Time.local(2009, 12, 4, 17, 0, 0))
|
72
|
+
@time_log.add TimeEntry.new("Project5", Time.local(2009, 12, 5, 9, 0, 0), Time.local(2009, 12, 5, 17, 0, 0))
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
it "should raise an error if attempting to delete an unknown index" do
|
77
|
+
lambda{@time_log.delete(100)}.should raise_error(ArgumentError)
|
78
|
+
@time_log.count.should == 5
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should not allow conflicting entries to be added" do
|
82
|
+
conflicting_entry = TimeEntry.new("Conflicting", Time.local(2009, 12, 2, 12, 0, 0), Time.local(2009, 12, 2, 13, 0, 0))
|
83
|
+
lambda { @time_log.add conflicting_entry }.should raise_error(ArgumentError)
|
84
|
+
@time_log.count.should == 5
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
context "editing items" do
|
90
|
+
|
91
|
+
before :all do
|
92
|
+
File.delete(TEST_FILE) if File.exists?(TEST_FILE)
|
93
|
+
@store = YAML::Store.new(TEST_FILE)
|
94
|
+
@time_log = TimeLog.new(@store)
|
95
|
+
|
96
|
+
@time_log.add TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
97
|
+
@time_log.add TimeEntry.new("Project2", Time.local(2009, 12, 2, 9, 0, 0), Time.local(2009, 12, 2, 17, 0, 0))
|
98
|
+
@time_log.add TimeEntry.new("Project3", Time.local(2009, 12, 3, 9, 0, 0), Time.local(2009, 12, 3, 17, 0, 0))
|
99
|
+
@time_log.add TimeEntry.new("Project4", Time.local(2009, 12, 4, 9, 0, 0), Time.local(2009, 12, 4, 17, 0, 0))
|
100
|
+
@time_log.add TimeEntry.new("Project5", Time.local(2009, 12, 5, 9, 0, 0), Time.local(2009, 12, 5, 17, 0, 0))
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should notify with an error if the edited item's index cannot be found" do
|
104
|
+
properties = { :project => "New Project" }
|
105
|
+
lambda{@time_log.update(100, properties)}.should raise_error(ArgumentError)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should allow updating of existing items" do
|
109
|
+
properties = {:project => "some new project"}
|
110
|
+
@time_log.update(2, properties)
|
111
|
+
@time_log.count.should == 5
|
112
|
+
|
113
|
+
entry = @time_log.find(2)
|
114
|
+
entry.project.should eql("some new project")
|
115
|
+
end
|
116
|
+
|
117
|
+
it "should allow updating of existing item start time" do
|
118
|
+
properties = {:start => Time.local(2009, 12, 2, 7, 0, 0)}
|
119
|
+
@time_log.update(2, properties)
|
120
|
+
@time_log.count.should == 5
|
121
|
+
|
122
|
+
entry = @time_log.find(2)
|
123
|
+
entry.start_time.should eql( Time.local(2009, 12, 2, 7, 0, 0))
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should notify with an error if the new times will overlap with existing items" do
|
127
|
+
properties = {:end => Time.local(2009, 12, 3, 10, 0, 0)}
|
128
|
+
lambda{@time_log.update(2, properties)}.should raise_error(ArgumentError)
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
132
|
+
|
133
|
+
context "extracting items" do
|
134
|
+
|
135
|
+
before :all do
|
136
|
+
File.delete(TEST_FILE) if File.exists?(TEST_FILE)
|
137
|
+
@store = YAML::Store.new(TEST_FILE)
|
138
|
+
@time_log = TimeLog.new(@store)
|
139
|
+
|
140
|
+
@time_log.add TimeEntry.new("Project1", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 17, 0, 0))
|
141
|
+
@time_log.add TimeEntry.new("Project2", Time.local(2009, 12, 2, 9, 0, 0), Time.local(2009, 12, 2, 17, 0, 0))
|
142
|
+
@time_log.add TimeEntry.new("Project3", Time.local(2009, 12, 3, 9, 0, 0), Time.local(2009, 12, 3, 17, 0, 0))
|
143
|
+
@time_log.add TimeEntry.new("Project4", Time.local(2009, 12, 4, 9, 0, 0), Time.local(2009, 12, 4, 17, 0, 0))
|
144
|
+
@time_log.add TimeEntry.new("Project5", Time.local(2009, 12, 5, 9, 0, 0), Time.local(2009, 12, 5, 17, 0, 0))
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should return an empty array if no items are in the range" do
|
148
|
+
entries = @time_log.extract_entries( Time.local(2009, 11, 1, 9, 0, 0), Time.local(2009, 11, 10, 17, 0, 0))
|
149
|
+
entries.should be_empty
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should return a collection of items that are covered by the range" do
|
153
|
+
entries = @time_log.extract_entries( Time.local(2009, 12, 2, 12, 0, 0), Time.local(2009, 12, 4, 12, 0, 0))
|
154
|
+
entries.count.should == 3
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should notify with an error if the new times will overlap with existing items" do
|
158
|
+
properties = {:end => Time.local(2009, 12, 3, 10, 0, 0)}
|
159
|
+
lambda{@time_log.update(2, properties)}.should raise_error(ArgumentError)
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe TimeReport do
|
4
|
+
|
5
|
+
before :each do
|
6
|
+
@entries =
|
7
|
+
[TimeEntry.new("ProjectA", Time.local(2009, 12, 1, 9, 0, 0), Time.local(2009, 12, 1, 12, 0, 0), "comment 1"),
|
8
|
+
TimeEntry.new("ProjectB", Time.local(2009, 12, 1, 1, 0, 0), Time.local(2009, 12, 1, 17, 0, 0), "comment 2"),
|
9
|
+
TimeEntry.new("ProjectA", Time.local(2009, 12, 3, 9, 0, 0), Time.local(2009, 12, 3, 17, 0, 0), "comment 3"),
|
10
|
+
TimeEntry.new("ProjectB", Time.local(2009, 12, 4, 9, 0, 0), Time.local(2009, 12, 4, 17, 0, 0), "comment 4"),
|
11
|
+
TimeEntry.new("ProjectC", Time.local(2009, 12, 5, 9, 0, 0), Time.local(2009, 12, 5, 17, 0, 0), "comment 5")]
|
12
|
+
@time_report = TimeReport.new(@entries)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be able to trim its entries to a specific time span" do
|
16
|
+
@time_report.trim(Time.local(2009, 12, 1, 11, 0, 0), Time.local(2009, 12, 5, 12, 0, 0))
|
17
|
+
@time_report.entries[0].start_time.should eql(Time.local(2009, 12, 1, 11, 0, 0))
|
18
|
+
@time_report.entries[-1].end_time.should eql(Time.local(2009, 12, 5, 12, 0, 0))
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should leave entries alone when the trim span is outside the entry range" do
|
22
|
+
@time_report.trim(Time.local(2009, 11, 1, 0, 0, 0), Time.local(2009, 12, 31, 0, 0, 0))
|
23
|
+
@time_report.entries[0].start_time.should eql(Time.local(2009, 12, 1, 9, 0, 0))
|
24
|
+
@time_report.entries[-1].end_time.should eql(Time.local(2009, 12, 5, 17, 0, 0))
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should be able to produce a detail report" do
|
28
|
+
command_options = {:detail => true, :start => Time.local(2009, 12, 1), :end => Time.local(2009, 12, 6)}
|
29
|
+
stream = StringIO.new
|
30
|
+
@time_report.report(command_options, stream)
|
31
|
+
stream.string.should eql( <<EOS
|
32
|
+
+----------------------------------------------------------------------------+
|
33
|
+
| Id | Project | Start - Stop | Hours | Comment |
|
34
|
+
+----------------------------------------------------------------------------+
|
35
|
+
| 0 | ProjectB | 12/01/2009 at 01:00 AM to 05:00 PM | 16h 0m | comment 2 |
|
36
|
+
| 0 | ProjectA | 12/01/2009 at 09:00 AM to 12:00 PM | 3h 0m | comment 1 |
|
37
|
+
| 0 | ProjectA | 12/03/2009 at 09:00 AM to 05:00 PM | 8h 0m | comment 3 |
|
38
|
+
| 0 | ProjectB | 12/04/2009 at 09:00 AM to 05:00 PM | 8h 0m | comment 4 |
|
39
|
+
| 0 | ProjectC | 12/05/2009 at 09:00 AM to 05:00 PM | 8h 0m | comment 5 |
|
40
|
+
+----------------------------------------------------------------------------+
|
41
|
+
EOS
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should be able to produce a detail report" do
|
46
|
+
command_options = {:detail => true, :start => Time.local(2009, 11, 1), :end => Time.local(2009, 12, 31)}
|
47
|
+
stream = StringIO.new
|
48
|
+
@time_report.report(command_options, stream)
|
49
|
+
stream.string.should eql( <<EOS
|
50
|
+
+----------------------------------------------------------------------------+
|
51
|
+
| Id | Project | Start - Stop | Hours | Comment |
|
52
|
+
+----------------------------------------------------------------------------+
|
53
|
+
| 0 | ProjectB | 12/01/2009 at 01:00 AM to 05:00 PM | 16h 0m | comment 2 |
|
54
|
+
| 0 | ProjectA | 12/01/2009 at 09:00 AM to 12:00 PM | 3h 0m | comment 1 |
|
55
|
+
| 0 | ProjectA | 12/03/2009 at 09:00 AM to 05:00 PM | 8h 0m | comment 3 |
|
56
|
+
| 0 | ProjectB | 12/04/2009 at 09:00 AM to 05:00 PM | 8h 0m | comment 4 |
|
57
|
+
| 0 | ProjectC | 12/05/2009 at 09:00 AM to 05:00 PM | 8h 0m | comment 5 |
|
58
|
+
+----------------------------------------------------------------------------+
|
59
|
+
EOS
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should be able to produce a summary report" do
|
64
|
+
command_options = {:summary => true, :start => Time.local(2009, 12, 1), :end => Time.local(2009, 12, 6)}
|
65
|
+
stream = StringIO.new
|
66
|
+
@time_report.report(command_options, stream)
|
67
|
+
stream.string.should eql( <<EOS
|
68
|
+
ProjectA 11h 0m
|
69
|
+
ProjectB 24h 0m
|
70
|
+
ProjectC 8h 0m
|
71
|
+
-----------------
|
72
|
+
Total 43h 0m
|
73
|
+
EOS
|
74
|
+
)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be able to produce a byday report" do
|
78
|
+
@entries << TimeEntry.new("ProjectB", Time.local(2009, 12, 1, 17, 0, 0), Time.local(2009, 12, 1, 19, 0, 0), "another comment")
|
79
|
+
|
80
|
+
command_options = {:byday => true, :start => Time.local(2009, 12, 1), :end => Time.local(2009, 12, 6)}
|
81
|
+
stream = StringIO.new
|
82
|
+
@time_report.report(command_options, stream)
|
83
|
+
stream.string.should eql( <<EOS
|
84
|
+
12/01/09
|
85
|
+
ProjectA 3h 0m
|
86
|
+
- comment 1
|
87
|
+
ProjectB 18h 0m
|
88
|
+
- comment 2
|
89
|
+
- another comment
|
90
|
+
12/03/09
|
91
|
+
ProjectA 8h 0m
|
92
|
+
- comment 3
|
93
|
+
12/04/09
|
94
|
+
ProjectB 8h 0m
|
95
|
+
- comment 4
|
96
|
+
12/05/09
|
97
|
+
ProjectC 8h 0m
|
98
|
+
- comment 5
|
99
|
+
EOS
|
100
|
+
)
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|