watch_tower 0.0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. data/.gitignore +10 -0
  2. data/.todo +33 -0
  3. data/.travis.yml +14 -0
  4. data/Gemfile +43 -0
  5. data/Guardfile +25 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +38 -0
  8. data/Rakefile +8 -0
  9. data/TODO +17 -0
  10. data/bin/watchtower +10 -0
  11. data/ci/adapters/jruby-mysql.yml +8 -0
  12. data/ci/adapters/jruby-postgresql.yml +6 -0
  13. data/ci/adapters/jruby-sqlite.yml +6 -0
  14. data/ci/adapters/ruby-mysql.yml +8 -0
  15. data/ci/adapters/ruby-postgresql.yml +6 -0
  16. data/ci/adapters/ruby-sqlite.yml +6 -0
  17. data/ci/travis.rb +102 -0
  18. data/lib/watch_tower.rb +60 -0
  19. data/lib/watch_tower/appscript.rb +22 -0
  20. data/lib/watch_tower/cli.rb +15 -0
  21. data/lib/watch_tower/cli/.gitkeep +0 -0
  22. data/lib/watch_tower/cli/install.rb +63 -0
  23. data/lib/watch_tower/cli/open.rb +24 -0
  24. data/lib/watch_tower/cli/start.rb +140 -0
  25. data/lib/watch_tower/config.rb +38 -0
  26. data/lib/watch_tower/core_ext.rb +4 -0
  27. data/lib/watch_tower/core_ext/.gitkeep +0 -0
  28. data/lib/watch_tower/editor.rb +17 -0
  29. data/lib/watch_tower/editor/.gitkeep +0 -0
  30. data/lib/watch_tower/editor/base_appscript.rb +34 -0
  31. data/lib/watch_tower/editor/base_ps.rb +6 -0
  32. data/lib/watch_tower/editor/textmate.rb +17 -0
  33. data/lib/watch_tower/editor/xcode.rb +22 -0
  34. data/lib/watch_tower/errors.rb +25 -0
  35. data/lib/watch_tower/eye.rb +79 -0
  36. data/lib/watch_tower/project.rb +14 -0
  37. data/lib/watch_tower/project/.gitkeep +0 -0
  38. data/lib/watch_tower/project/any_based.rb +22 -0
  39. data/lib/watch_tower/project/git_based.rb +86 -0
  40. data/lib/watch_tower/project/init.rb +38 -0
  41. data/lib/watch_tower/project/path_based.rb +144 -0
  42. data/lib/watch_tower/server.rb +62 -0
  43. data/lib/watch_tower/server/.gitkeep +0 -0
  44. data/lib/watch_tower/server/app.rb +37 -0
  45. data/lib/watch_tower/server/assets/images/WatchTower.jpg +0 -0
  46. data/lib/watch_tower/server/assets/images/percentage.png +0 -0
  47. data/lib/watch_tower/server/assets/javascripts/application.js +3 -0
  48. data/lib/watch_tower/server/assets/javascripts/percentage.coffee +8 -0
  49. data/lib/watch_tower/server/assets/stylesheets/application.css +7 -0
  50. data/lib/watch_tower/server/assets/stylesheets/global.sass +71 -0
  51. data/lib/watch_tower/server/assets/stylesheets/project.sass +59 -0
  52. data/lib/watch_tower/server/configurations.rb +10 -0
  53. data/lib/watch_tower/server/configurations/asset.rb +43 -0
  54. data/lib/watch_tower/server/database.rb +105 -0
  55. data/lib/watch_tower/server/db/migrate/001_create_projects.rb +15 -0
  56. data/lib/watch_tower/server/db/migrate/002_create_files.rb +16 -0
  57. data/lib/watch_tower/server/db/migrate/003_create_time_entries.rb +12 -0
  58. data/lib/watch_tower/server/db/migrate/004_create_durations.rb +14 -0
  59. data/lib/watch_tower/server/db/migrate/005_add_hash_to_time_entries.rb +6 -0
  60. data/lib/watch_tower/server/db/migrate/006_add_hash_to_files.rb +6 -0
  61. data/lib/watch_tower/server/decorator.rb +21 -0
  62. data/lib/watch_tower/server/decorator/application_decorator.rb +91 -0
  63. data/lib/watch_tower/server/decorator/file_decorator.rb +38 -0
  64. data/lib/watch_tower/server/decorator/project_decorator.rb +51 -0
  65. data/lib/watch_tower/server/helpers.rb +13 -0
  66. data/lib/watch_tower/server/helpers/asset.rb +29 -0
  67. data/lib/watch_tower/server/helpers/improved_partials.rb +41 -0
  68. data/lib/watch_tower/server/models/duration.rb +11 -0
  69. data/lib/watch_tower/server/models/file.rb +31 -0
  70. data/lib/watch_tower/server/models/project.rb +17 -0
  71. data/lib/watch_tower/server/models/time_entry.rb +64 -0
  72. data/lib/watch_tower/server/public/assets/WatchTower-4d6de11e1bd34165ad91ac46fb711bf3.jpg +0 -0
  73. data/lib/watch_tower/server/public/assets/application-7829b53b5ece1a16d22dc3d00f329023.css +107 -0
  74. data/lib/watch_tower/server/public/assets/application-e0e6b7731aade460f680331e65cf0682.js +9359 -0
  75. data/lib/watch_tower/server/public/assets/percentage-d8589e21a5fc85d32a445f531ff8ab95.png +0 -0
  76. data/lib/watch_tower/server/vendor/assets/javascripts/jquery-ui.js +11729 -0
  77. data/lib/watch_tower/server/vendor/assets/javascripts/jquery.js +8981 -0
  78. data/lib/watch_tower/server/vendor/assets/javascripts/jquery_ujs.js +363 -0
  79. data/lib/watch_tower/server/views/.gitkeep +0 -0
  80. data/lib/watch_tower/server/views/_file.haml +9 -0
  81. data/lib/watch_tower/server/views/_project.haml +13 -0
  82. data/lib/watch_tower/server/views/index.haml +7 -0
  83. data/lib/watch_tower/server/views/layout.haml +32 -0
  84. data/lib/watch_tower/server/views/project.haml +12 -0
  85. data/lib/watch_tower/templates/config.yml +146 -0
  86. data/lib/watch_tower/templates/watchtower.plist +23 -0
  87. data/lib/watch_tower/version.rb +8 -0
  88. data/spec/factories.rb +45 -0
  89. data/spec/spec_helper.rb +26 -0
  90. data/spec/support/active_record.rb +44 -0
  91. data/spec/support/factory_girl.rb +6 -0
  92. data/spec/support/launchy.rb +3 -0
  93. data/spec/support/sinatra.rb +10 -0
  94. data/spec/support/timecop.rb +7 -0
  95. data/spec/watch_tower/appscript_spec.rb +6 -0
  96. data/spec/watch_tower/cli/install_spec.rb +16 -0
  97. data/spec/watch_tower/cli/open_spec.rb +14 -0
  98. data/spec/watch_tower/cli/start_spec.rb +17 -0
  99. data/spec/watch_tower/cli_spec.rb +15 -0
  100. data/spec/watch_tower/config_spec.rb +25 -0
  101. data/spec/watch_tower/editor/textmate_spec.rb +43 -0
  102. data/spec/watch_tower/editor/xcode_spec.rb +43 -0
  103. data/spec/watch_tower/editor_spec.rb +19 -0
  104. data/spec/watch_tower/eye_spec.rb +130 -0
  105. data/spec/watch_tower/project/git_based_spec.rb +131 -0
  106. data/spec/watch_tower/project/path_based_spec.rb +111 -0
  107. data/spec/watch_tower/project_spec.rb +82 -0
  108. data/spec/watch_tower/server/app_spec.rb +186 -0
  109. data/spec/watch_tower/server/decorator/project_decorator_spec.rb +60 -0
  110. data/spec/watch_tower/server/models/file_spec.rb +284 -0
  111. data/spec/watch_tower/server/models/project_spec.rb +165 -0
  112. data/spec/watch_tower/server/models/time_entry_spec.rb +37 -0
  113. data/spec/watch_tower/server_spec.rb +4 -0
  114. data/watch_tower.gemspec +80 -0
  115. metadata +450 -0
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ module Server
4
+ module Decorator
5
+ describe ProjectDecorator do
6
+ before(:each) do
7
+ @project = FactoryGirl.create :project
8
+ end
9
+
10
+ subject { ProjectDecorator.find(@project.id) }
11
+
12
+ it "should return a formatted elapsed time" do
13
+ time = 1.day + 2.hours + 3.minutes + 34.seconds
14
+ subject.stubs(:elapsed_time).returns(time)
15
+ subject.elapsed.should == '1 day, 2 hours, 3 minutes and 34 seconds'
16
+ end
17
+
18
+ describe "Application Decorator" do
19
+ describe "#humanize_time" do
20
+ it "should return 1 second" do
21
+ subject.send(:humanize_time, 1).should == '1 second'
22
+ end
23
+
24
+ it "should return 2 seconds" do
25
+ subject.send(:humanize_time, 2).should == '2 seconds'
26
+ end
27
+
28
+ it "should return 1 minute" do
29
+ subject.send(:humanize_time, 1.minute).should == '1 minute'
30
+ end
31
+
32
+ it "should return 2 minutes" do
33
+ subject.send(:humanize_time, 2.minutes).should == '2 minutes'
34
+ end
35
+
36
+ it "should return 1 hour" do
37
+ subject.send(:humanize_time, 1.hour).should == '1 hour'
38
+ end
39
+
40
+ it "should return 2 hours" do
41
+ subject.send(:humanize_time, 2.hours).should == '2 hours'
42
+ end
43
+
44
+ it "should return 1 day" do
45
+ subject.send(:humanize_time, 1.day).should == '1 day'
46
+ end
47
+
48
+ it "should return 2 days" do
49
+ subject.send(:humanize_time, 2.days).should == '2 days'
50
+ end
51
+
52
+ it "should return 1 day, 2 hours, 3 minutes and 34 seconds" do
53
+ time = 1.day + 2.hours + 3.minutes + 34.seconds
54
+ subject.send(:humanize_time, time).should == '1 day, 2 hours, 3 minutes and 34 seconds'
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,284 @@
1
+ require 'spec_helper'
2
+
3
+ module Server
4
+ describe File do
5
+ describe "Attributes" do
6
+ it { should respond_to :path }
7
+ it { should respond_to :elapsed_time }
8
+ it { should respond_to :time_entries_count }
9
+ end
10
+
11
+ describe "Validations" do
12
+ it { should_not be_valid }
13
+
14
+ it "should require an path" do
15
+ m = FactoryGirl.build :file, path: nil
16
+ m.should_not be_valid
17
+ end
18
+
19
+ it "should require a project" do
20
+ m = FactoryGirl.build :file, project: nil
21
+ m.should_not be_valid
22
+ end
23
+
24
+ it "should not require a hash" do
25
+ m = FactoryGirl.build :file, file_hash: nil
26
+ m.should be_valid
27
+ end
28
+
29
+ it "should have a unique path for each project" do
30
+ p = FactoryGirl.create :project
31
+ FactoryGirl.create :file, path: '/path/to/file.rb', project: p
32
+ m = FactoryGirl.build :file, path: '/path/to/file.rb', project: p
33
+ m.should_not be_valid
34
+ end
35
+
36
+ it "should be valid if attributes requirements are met" do
37
+ m = FactoryGirl.build :file
38
+ m.should be_valid
39
+ end
40
+ end
41
+
42
+ describe "Associations" do
43
+ before(:each) do
44
+ @file = FactoryGirl.create :file
45
+ end
46
+
47
+ it { should respond_to :project }
48
+ it { should respond_to :time_entries }
49
+
50
+ it "should increment the counter cache" do
51
+ 10.times do
52
+ FactoryGirl.create :time_entry, file: @file
53
+ end
54
+
55
+ @file.reload.time_entries_count.should == 10
56
+ end
57
+
58
+ it "should belong to a project" do
59
+ project = FactoryGirl.create :project
60
+ file = FactoryGirl.create :file, project: project
61
+
62
+ file.project.should == project
63
+ end
64
+ end
65
+
66
+ describe "TimeEntries count" do
67
+ before(:each) do
68
+ @file = FactoryGirl.create :file
69
+ end
70
+
71
+ it "should calculate elapsed time" do
72
+ 3.times do
73
+ Timecop.freeze(Time.now + 1)
74
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
75
+ end
76
+
77
+ @file.reload
78
+ @file.elapsed_time.should == 2
79
+ end
80
+
81
+ it "should skip the one with pause time" do
82
+ 3.times do
83
+ Timecop.freeze(Time.now + 1)
84
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
85
+ end
86
+
87
+ Timecop.freeze(Time.now + @file.time_entries.first.send(:pause_time) + 1)
88
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
89
+
90
+ 3.times do
91
+ Timecop.freeze(Time.now + 1)
92
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
93
+ end
94
+
95
+ @file.reload
96
+ @file.elapsed_time.should == 5
97
+ end
98
+
99
+ it "should not count the time entries of another file" do
100
+ 3.times do
101
+ Timecop.freeze(Time.now + 1)
102
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
103
+ end
104
+
105
+ 3.times do
106
+ Timecop.freeze(Time.now + 1)
107
+ FactoryGirl.create :time_entry, mtime: Time.now
108
+ end
109
+
110
+ @file.reload
111
+ @file.elapsed_time.should == 2
112
+ end
113
+
114
+ it "should add duration to a different day (2 days)." do
115
+ # Create initial time entries
116
+ 3.times do
117
+ Timecop.freeze(Time.now + 1)
118
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
119
+ end
120
+
121
+ # Go ahead one day
122
+ Timecop.freeze(Time.now + 1.day)
123
+
124
+ # Add 3 more time entries
125
+ 3.times do
126
+ Timecop.freeze(Time.now + 1)
127
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
128
+ end
129
+
130
+ @file.reload
131
+ @file.elapsed_time.should == 4
132
+ @file.durations.size.should == 2
133
+ end
134
+
135
+ it "should correctly record dates" do
136
+ # Record the date of the first day
137
+ Timecop.freeze(Time.now)
138
+ current_day = Time.now.to_date
139
+
140
+ # Create initial time entries
141
+ 3.times do
142
+ Timecop.freeze(Time.now + 1)
143
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
144
+ end
145
+
146
+ # Go ahead one day
147
+ Timecop.freeze(Time.now + 1.day)
148
+ next_day = Time.now.to_date
149
+
150
+ # Add 3 more time entries
151
+ 3.times do
152
+ Timecop.freeze(Time.now + 1)
153
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
154
+ end
155
+
156
+ @file.reload
157
+ @file.durations.order('id ASC').first.date.should == current_day
158
+ @file.durations.order('id ASC').last.date.should == next_day
159
+ end
160
+
161
+ it "should not add elapsed time to the count if the file's has has not changed" do
162
+ # Freeze the time
163
+ Timecop.freeze(Time.now)
164
+ # Create the first time entry
165
+ t1 = FactoryGirl.create :time_entry, file: @file, file_hash: @file.file_hash
166
+ # Go ahead 10 minutes
167
+ Timecop.freeze(Time.now + 10.minutes)
168
+ # Create the second time entry with the same file and hash
169
+ FactoryGirl.create :time_entry, file: @file, file_hash: @file.file_hash
170
+
171
+ @file.elapsed_time.should == 0
172
+ end
173
+
174
+ it "should update the hash of the file with the last time entry" do
175
+ # Freeze the time
176
+ Timecop.freeze(Time.now)
177
+ # Create the first time entry
178
+ t1 = FactoryGirl.create :time_entry, file: @file
179
+ # Go ahead 10 minutes
180
+ Timecop.freeze(Time.now + 10.minutes)
181
+ # Create the second time entry with the same file and hash
182
+ FactoryGirl.create :time_entry, file: @file, file_hash: t1.file_hash
183
+
184
+ @file.file_hash.should == t1.file_hash
185
+ end
186
+
187
+ end
188
+
189
+ describe "scopes" do
190
+ before(:each) do
191
+ @files = 3.times.collect{ FactoryGirl.create :file }
192
+ end
193
+
194
+ it "should have the default scope to" do
195
+ 10.times do |n|
196
+ file = @files.first
197
+ Timecop.freeze(Time.now + n * 2)
198
+ FactoryGirl.create :time_entry, file: file, mtime: Time.now
199
+ end
200
+
201
+ 10.times do |n|
202
+ file = @files[1]
203
+ Timecop.freeze(Time.now + n * 10)
204
+ FactoryGirl.create :time_entry, file: file, mtime: Time.now
205
+ end
206
+
207
+ 10.times do |n|
208
+ file = @files.last
209
+ Timecop.freeze(Time.now + n * 5)
210
+ FactoryGirl.create :time_entry, file: file, mtime: Time.now
211
+ end
212
+
213
+ File.all.first.should == @files[1]
214
+ end
215
+
216
+ it "should have a scope worked_on" do
217
+ File.should respond_to(:worked_on)
218
+ end
219
+
220
+ it "should have a scope worked_on that returns all projects that do not have empty time_entries" do
221
+ 5.times do
222
+ FactoryGirl.create :time_entry, file: @files[0]
223
+ end
224
+
225
+ 5.times do
226
+ FactoryGirl.create :time_entry, file: @files[1]
227
+ end
228
+
229
+ File.worked_on.should_not include(@files.last)
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "Methods" do
235
+ before(:each) do
236
+ @project = FactoryGirl.create :project
237
+ @files = []
238
+ 2.times do
239
+ @files << FactoryGirl.create(:file, project: @project)
240
+ 2.times do
241
+ FactoryGirl.create :time_entry, file: @files.last
242
+ end
243
+ end
244
+ end
245
+
246
+ describe "one project" do
247
+ describe "#sum_elapsed_time" do
248
+ it "should return the sum of all elapsed times of all the files for the same project" do
249
+ @project.files.sum_elapsed_time.should == @files.inject(0) {|s, f| s += f.elapsed_time }
250
+ end
251
+ end
252
+
253
+ describe "#percent" do
254
+ it "should return 50" do
255
+ @project.files.first.percent.should == 50
256
+ end
257
+ end
258
+ end
259
+
260
+ describe "two projects" do
261
+ before(:each) do
262
+ @other_files = []
263
+ 2.times do
264
+ @other_files << FactoryGirl.create(:file)
265
+ 2.times do
266
+ FactoryGirl.create :time_entry, file: @other_files.last
267
+ end
268
+ end
269
+
270
+ describe "#sum_elapsed_time" do
271
+ it "should return the sum of all elapsed times of all the files for the same project" do
272
+ @project.files.sum_elapsed_time.should == @files.inject(0) {|s, f| s += f.elapsed_time }
273
+ end
274
+ end
275
+
276
+ describe "#percent" do
277
+ it "should return 50" do
278
+ @project.files.first.percent.should == 50
279
+ end
280
+ end
281
+ end
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+
3
+ module Server
4
+ describe Project do
5
+ describe "Attributes" do
6
+ it { should respond_to :name }
7
+ it { should respond_to :path }
8
+ it { should respond_to :files_count }
9
+ end
10
+
11
+ describe "Methods" do
12
+ it { should respond_to :elapsed_time }
13
+ end
14
+
15
+ describe "Validations" do
16
+ it { should_not be_valid }
17
+
18
+ it "should require a name" do
19
+ m = FactoryGirl.build :project, name: nil
20
+ m.should_not be_valid
21
+ end
22
+
23
+ it "should require a path" do
24
+ m = FactoryGirl.build :project, path: nil
25
+ m.should_not be_valid
26
+ end
27
+
28
+ it "should be valid if attributes requirements are met" do
29
+ m = FactoryGirl.build :project
30
+ m.should be_valid
31
+ end
32
+ end
33
+
34
+ describe "Associations" do
35
+ before(:each) do
36
+ @project = FactoryGirl.create :project
37
+ end
38
+ it { should respond_to :files }
39
+ it { should respond_to :time_entries }
40
+
41
+ it "should increment the counter cache" do
42
+ 10.times do
43
+ FactoryGirl.create :file, project: @project
44
+ end
45
+
46
+ @project.reload.files_count.should == 10
47
+ end
48
+
49
+ it "should have time_entries through files" # do
50
+ # file1 = FactoryGirl.create :file, project: @project
51
+ # file2 = FactoryGirl.create :file, project: @project
52
+ #
53
+ # 10.times do
54
+ # FactoryGirl.create :time_entry, file: file1
55
+ # end
56
+ #
57
+ # 10.times do
58
+ # FactoryGirl.create :time_entry, file: file2
59
+ # end
60
+ #
61
+ # @project.reload.time_entries.size.should == 20
62
+ # end
63
+ end
64
+
65
+ describe "TimeEntries count" do
66
+ before(:each) do
67
+ @project = FactoryGirl.create :project
68
+ @file = FactoryGirl.create :file, project: @project
69
+ end
70
+
71
+ it "should calculate elapsed time" do
72
+ 3.times do
73
+ Timecop.freeze(Time.now + 1)
74
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
75
+ end
76
+
77
+ @project.reload
78
+ @project.elapsed_time.should == 2
79
+ end
80
+
81
+ it "should skip the one with pause time" do
82
+ 3.times do
83
+ Timecop.freeze(Time.now + 1)
84
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
85
+ end
86
+
87
+ Timecop.freeze(Time.now + @file.time_entries.first.send(:pause_time) + 1)
88
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
89
+
90
+ 3.times do
91
+ Timecop.freeze(Time.now + 1)
92
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
93
+ end
94
+
95
+ @project.reload
96
+ @project.elapsed_time.should == 5
97
+ end
98
+
99
+ it "should not count the time entries of another file" do
100
+ 3.times do
101
+ Timecop.freeze(Time.now + 1)
102
+ FactoryGirl.create :time_entry, file: @file, mtime: Time.now
103
+ end
104
+
105
+ 3.times do
106
+ Timecop.freeze(Time.now + 1)
107
+ FactoryGirl.create :time_entry, mtime: Time.now
108
+ end
109
+
110
+ @project.reload
111
+ @project.elapsed_time.should == 2
112
+ end
113
+ end
114
+
115
+ describe "scopes" do
116
+ before(:each) do
117
+ @projects = 3.times.collect do
118
+ project = FactoryGirl.create :project
119
+ FactoryGirl.create :file, project: project
120
+ project.reload
121
+ end
122
+ end
123
+
124
+ it "should have the default scope to" do
125
+ file = @projects.first.files.first
126
+ 10.times do |n|
127
+ Timecop.freeze(Time.now + n * 2)
128
+ FactoryGirl.create :time_entry, file: file, mtime: Time.now
129
+ end
130
+
131
+ file = @projects[1].files.first
132
+ 10.times do |n|
133
+ Timecop.freeze(Time.now + n * 10)
134
+ FactoryGirl.create :time_entry, file: file, mtime: Time.now
135
+ end
136
+
137
+ file = @projects.last.files.first
138
+ 10.times do |n|
139
+ Timecop.freeze(Time.now + n * 5)
140
+ FactoryGirl.create :time_entry, file: file, mtime: Time.now
141
+ end
142
+
143
+ Project.all.first.should == @projects[1]
144
+ end
145
+
146
+ it "should have a scope worked_on" do
147
+ Project.should respond_to(:worked_on)
148
+ end
149
+
150
+ it "should have a scope worked_on that returns all projects that do not have empty time_entries" do
151
+ file = @projects[0].files.first
152
+ 5.times do
153
+ FactoryGirl.create :time_entry, file: file
154
+ end
155
+
156
+ file = @projects[1].files.first
157
+ 5.times do
158
+ FactoryGirl.create :time_entry, file: file
159
+ end
160
+
161
+ Project.worked_on.should_not include(@projects.last)
162
+ end
163
+ end
164
+ end
165
+ end