git_statistics 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +7 -0
- data/CHANGELOG.md +6 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +15 -0
- data/Guardfile +7 -0
- data/README.md +7 -2
- data/git_statistics.gemspec +1 -0
- data/lib/git_statistics/collector.rb +130 -245
- data/lib/git_statistics/commits.rb +19 -24
- data/lib/git_statistics/initialize.rb +1 -0
- data/lib/git_statistics/results.rb +96 -0
- data/lib/git_statistics/utilities.rb +108 -0
- data/lib/git_statistics/version.rb +1 -1
- data/lib/git_statistics.rb +7 -4
- data/spec/collector_spec.rb +365 -0
- data/spec/commits_spec.rb +238 -0
- data/spec/fixtures/commit_buffer_changes.txt +9 -0
- data/spec/fixtures/commit_buffer_information.txt +1 -0
- data/spec/fixtures/commit_buffer_information_first.txt +1 -0
- data/spec/fixtures/commit_buffer_information_with_merge.txt +1 -0
- data/spec/fixtures/commit_buffer_whole.txt +6 -0
- data/spec/fixtures/git_many_branches.txt +2 -0
- data/spec/fixtures/git_zero_branches.txt +1 -0
- data/spec/fixtures/header_output.txt +4 -0
- data/spec/fixtures/language_data_output.txt +2 -0
- data/spec/fixtures/multiple_authors.json +1 -0
- data/spec/fixtures/single_author_pretty.json +79 -0
- data/spec/fixtures/summary_output.txt +17 -0
- data/spec/results_spec.rb +143 -0
- data/spec/utilities_spec.rb +169 -0
- metadata +54 -2
@@ -0,0 +1,365 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include GitStatistics
|
3
|
+
|
4
|
+
describe Collector do
|
5
|
+
|
6
|
+
collector = Collector.new(false)
|
7
|
+
|
8
|
+
describe "#collect_branches" do
|
9
|
+
context "with many branches" do
|
10
|
+
branches = collector.collect_branches(fixture("git_many_branches.txt"))
|
11
|
+
it {branches.size.should == 2}
|
12
|
+
it {branches[0].should == "issue_2"}
|
13
|
+
it {branches[1].should == "master"}
|
14
|
+
end
|
15
|
+
|
16
|
+
context "with zero branches" do
|
17
|
+
branches = collector.collect_branches(fixture("git_zero_branches.txt"))
|
18
|
+
it {branches.size.should == 1}
|
19
|
+
it {branches[0].should == "master"}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#extract_change_file" do
|
24
|
+
context "with a simple changed file" do
|
25
|
+
line = "37 30 lib/file.rb"
|
26
|
+
file = collector.extract_change_file(line)
|
27
|
+
it {file[:additions].should == 37}
|
28
|
+
it {file[:deletions].should == 30}
|
29
|
+
it {file[:file].should == "lib/file.rb"}
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with a simple rename/copy changed file" do
|
33
|
+
line = "11 3 old_file.rb => lib/file.rb"
|
34
|
+
file = collector.extract_change_file(line)
|
35
|
+
it {file[:additions].should == 11}
|
36
|
+
it {file[:deletions].should == 3}
|
37
|
+
it {file[:file].should == "lib/file.rb"}
|
38
|
+
it {file[:old_file].should == "old_file.rb"}
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with a complex rename/copy changed file" do
|
42
|
+
line = "- - lib/{old_dir => new_dir}/file.rb"
|
43
|
+
file = collector.extract_change_file(line)
|
44
|
+
it {file[:additions].should == 0}
|
45
|
+
it {file[:deletions].should == 0}
|
46
|
+
it {file[:file].should == "lib/new_dir/file.rb"}
|
47
|
+
it {file[:old_file].should == "lib/old_dir/file.rb"}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe "#extract_create_delete_file" do
|
52
|
+
context "with a create changed file" do
|
53
|
+
line = "create mode 100644 lib/dir/file.rb"
|
54
|
+
file = collector.extract_create_delete_file(line)
|
55
|
+
it {file[:status].should == "create"}
|
56
|
+
it {file[:file].should == "lib/dir/file.rb"}
|
57
|
+
end
|
58
|
+
|
59
|
+
context "with a delete changed file" do
|
60
|
+
line = "delete mode 100644 lib/file.rb"
|
61
|
+
file = collector.extract_create_delete_file(line)
|
62
|
+
it {file[:status].should == "delete"}
|
63
|
+
it {file[:file].should == "lib/file.rb"}
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#extract_rename_copy_file" do
|
68
|
+
context "with a rename changed file" do
|
69
|
+
line = "rename lib/{old_dir => new_dir}/file.rb (100%)"
|
70
|
+
file = collector.extract_rename_copy_file(line)
|
71
|
+
it {file[:status].should == "rename"}
|
72
|
+
it {file[:old_file].should == "lib/old_dir/file.rb"}
|
73
|
+
it {file[:new_file].should == "lib/new_dir/file.rb"}
|
74
|
+
it {file[:similar].should == 100}
|
75
|
+
end
|
76
|
+
|
77
|
+
context "with a copy changed file" do
|
78
|
+
line = "copy lib/dir/{old_file.rb => new_file.rb} (75%)"
|
79
|
+
file = collector.extract_rename_copy_file(line)
|
80
|
+
it {file[:status].should == "copy"}
|
81
|
+
it {file[:old_file].should == "lib/dir/old_file.rb"}
|
82
|
+
it {file[:new_file].should == "lib/dir/new_file.rb"}
|
83
|
+
it {file[:similar].should == 75}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#acquire_commit_data" do
|
88
|
+
context "no parent, first commit" do
|
89
|
+
collector.commits.clear
|
90
|
+
input = fixture("commit_buffer_information_first.txt").read
|
91
|
+
commit_data = collector.acquire_commit_data(input)
|
92
|
+
it {commit_data[:sha].should == "111111aa111a11111a11aa11aaaa11a111111a11"}
|
93
|
+
it {commit_data[:data][:author].should == "Test Author"}
|
94
|
+
it {commit_data[:data][:author_email].should == "author@test.com"}
|
95
|
+
it {commit_data[:data][:time].should == "2011-01-11 11:11:11 +0000"}
|
96
|
+
it {commit_data[:data][:merge].should be_false}
|
97
|
+
end
|
98
|
+
|
99
|
+
context "without merge, one parent" do
|
100
|
+
collector.commits.clear
|
101
|
+
input = fixture("commit_buffer_information.txt").read
|
102
|
+
commit_data = collector.acquire_commit_data(input)
|
103
|
+
it {commit_data[:sha].should == "111111aa111a11111a11aa11aaaa11a111111a11"}
|
104
|
+
it {commit_data[:data][:author].should == "Test Author"}
|
105
|
+
it {commit_data[:data][:author_email].should == "author@test.com"}
|
106
|
+
it {commit_data[:data][:time].should == "2011-01-11 11:11:11 +0000"}
|
107
|
+
it {commit_data[:data][:merge].should be_false}
|
108
|
+
end
|
109
|
+
|
110
|
+
context "with merge, two parents" do
|
111
|
+
collector.commits.clear
|
112
|
+
input = fixture("commit_buffer_information_with_merge.txt").read
|
113
|
+
commit_data = collector.acquire_commit_data(input)
|
114
|
+
it {commit_data[:sha].should == "111111aa111a11111a11aa11aaaa11a111111a11"}
|
115
|
+
it {commit_data[:data][:author].should == "Test Author"}
|
116
|
+
it {commit_data[:data][:author_email].should == "author@test.com"}
|
117
|
+
it {commit_data[:data][:time].should == "2011-01-11 11:11:11 +0000"}
|
118
|
+
it {commit_data[:data][:merge].should be_true}
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe "#identify_changed_files" do
|
123
|
+
context "with no changes" do
|
124
|
+
buffer = []
|
125
|
+
files = collector.identify_changed_files(buffer)
|
126
|
+
it {files.size.should == 0}
|
127
|
+
it {files[0].should == nil}
|
128
|
+
end
|
129
|
+
|
130
|
+
context "with all types (create,delete,rename,copy) of files" do
|
131
|
+
# Create buffer which is an array of cleaned lines
|
132
|
+
buffer = []
|
133
|
+
fixture("commit_buffer_changes.txt").readlines.each do |line|
|
134
|
+
buffer << Utilities.clean_string(line)
|
135
|
+
end
|
136
|
+
|
137
|
+
files = collector.identify_changed_files(buffer)
|
138
|
+
it {files.size.should == 5}
|
139
|
+
|
140
|
+
it {files[0][:additions].should == 45}
|
141
|
+
it {files[0][:deletions].should == 1}
|
142
|
+
it {files[0][:file].should == "dir/README"}
|
143
|
+
|
144
|
+
it {files[1][:additions].should == 6}
|
145
|
+
it {files[1][:deletions].should == 5}
|
146
|
+
it {files[1][:old_file].should == "dir/lib/old_dir/copy_file.rb"}
|
147
|
+
it {files[1][:file].should == "dir/lib/new_dir/copy_file.rb"}
|
148
|
+
it {files[1][:status].should == "copy"}
|
149
|
+
|
150
|
+
it {files[2][:additions].should == 0}
|
151
|
+
it {files[2][:deletions].should == 0}
|
152
|
+
it {files[2][:old_file].should == "dir/lib/rename/old_file.rb"}
|
153
|
+
it {files[2][:file].should == "dir/lib/rename/new_file.rb"}
|
154
|
+
it {files[2][:status].should == "rename"}
|
155
|
+
|
156
|
+
it {files[3][:additions].should == 0}
|
157
|
+
it {files[3][:deletions].should == 127}
|
158
|
+
it {files[3][:file].should == "dir/lib/delete_file.rb"}
|
159
|
+
it {files[3][:status].should == "delete"}
|
160
|
+
|
161
|
+
it {files[4][:additions].should == 60}
|
162
|
+
it {files[4][:deletions].should == 0}
|
163
|
+
it {files[4][:file].should == "dir/lib/create_file.rb"}
|
164
|
+
it {files[4][:status].should == "create"}
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
describe "#extract_commit" do
|
169
|
+
context "with valid buffer" do
|
170
|
+
collector.commits.clear
|
171
|
+
buffer = []
|
172
|
+
fixture("commit_buffer_whole.txt").readlines.each do |line|
|
173
|
+
buffer << Utilities.clean_string(line)
|
174
|
+
end
|
175
|
+
data = collector.extract_commit(buffer)
|
176
|
+
|
177
|
+
it {data[:author].should == "Kevin Jalbert"}
|
178
|
+
it {data[:author_email].should == "kevin.j.jalbert@gmail.com"}
|
179
|
+
it {data[:time].should == "2012-04-12 14:13:56 -0400"}
|
180
|
+
|
181
|
+
it {data[:merge].should == false}
|
182
|
+
it {data[:additions].should == 30}
|
183
|
+
it {data[:deletions].should == 2}
|
184
|
+
it {data[:create].should == 1}
|
185
|
+
|
186
|
+
it {data[:files][0][:name].should == "Gemfile"}
|
187
|
+
it {data[:files][0][:additions].should == 0}
|
188
|
+
it {data[:files][0][:deletions].should == 1}
|
189
|
+
it {data[:files][0][:status].should == nil}
|
190
|
+
it {data[:files][0][:binary].should == false}
|
191
|
+
it {data[:files][0][:image].should == false}
|
192
|
+
it {data[:files][0][:vendored].should == false}
|
193
|
+
it {data[:files][0][:generated].should == false}
|
194
|
+
it {data[:files][0][:language].should == "Ruby"}
|
195
|
+
|
196
|
+
it {data[:files][1][:name].should == "Gemfile.lock"}
|
197
|
+
it {data[:files][1][:additions].should == 30}
|
198
|
+
it {data[:files][1][:deletions].should == 0}
|
199
|
+
it {data[:files][1][:status].should == "create"}
|
200
|
+
it {data[:files][1][:binary].should == false}
|
201
|
+
it {data[:files][1][:image].should == false}
|
202
|
+
it {data[:files][1][:vendored].should == false}
|
203
|
+
it {data[:files][1][:generated].should == true}
|
204
|
+
it {data[:files][1][:language].should == "Unknown"}
|
205
|
+
|
206
|
+
it {data[:files][2][:name].should == "lib/git_statistics/initialize.rb"}
|
207
|
+
it {data[:files][2][:additions].should == 0}
|
208
|
+
it {data[:files][2][:deletions].should == 1}
|
209
|
+
it {data[:files][2][:status].should == nil}
|
210
|
+
it {data[:files][2][:binary].should == false}
|
211
|
+
it {data[:files][2][:image].should == false}
|
212
|
+
it {data[:files][2][:vendored].should == false}
|
213
|
+
it {data[:files][2][:generated].should == false}
|
214
|
+
it {data[:files][2][:language].should == "Ruby"}
|
215
|
+
end
|
216
|
+
|
217
|
+
context "with buffer that has no file changes" do
|
218
|
+
collector.commits.clear
|
219
|
+
buffer = []
|
220
|
+
fixture("commit_buffer_information.txt").readlines.each do |line|
|
221
|
+
buffer << Utilities.clean_string(line)
|
222
|
+
end
|
223
|
+
data = collector.extract_commit(buffer)
|
224
|
+
|
225
|
+
it {data.should == nil}
|
226
|
+
end
|
227
|
+
|
228
|
+
context "with invalid buffer" do
|
229
|
+
collector.commits.clear
|
230
|
+
buffer = "invalid input"
|
231
|
+
data = collector.extract_commit(buffer)
|
232
|
+
|
233
|
+
it {data.should == nil}
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
describe "#fall_back_collect_commit" do
|
238
|
+
context "with valid sha" do
|
239
|
+
buffer = collector.fall_back_collect_commit("260bc61e2c42930d91f3503c5849b0a2351275cf")
|
240
|
+
|
241
|
+
# Create buffer which is an array of cleaned lines
|
242
|
+
expected = []
|
243
|
+
fixture("commit_buffer_whole.txt").readlines.each do |line|
|
244
|
+
expected << Utilities.clean_string(line)
|
245
|
+
end
|
246
|
+
|
247
|
+
it {buffer.should == expected}
|
248
|
+
end
|
249
|
+
|
250
|
+
context "with invalid sha" do
|
251
|
+
buffer = collector.fall_back_collect_commit("111111aa111a11111a11aa11aaaa11a111111a11")
|
252
|
+
it {buffer.should == nil}
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
describe "#get_blob" do
|
257
|
+
sha = "695b487432e8a1ede765b4e3efda088ab87a77f8" # Commit within repository
|
258
|
+
|
259
|
+
context "with valid blob" do
|
260
|
+
file = {:file => "Gemfile.lock"}
|
261
|
+
blob = collector.get_blob(sha, file)
|
262
|
+
|
263
|
+
it {blob.instance_of?(Grit::Blob).should be_true}
|
264
|
+
it {blob.name.should == file[:file].split(File::Separator).last}
|
265
|
+
end
|
266
|
+
|
267
|
+
context "with invalid blob" do
|
268
|
+
file = {:file => "dir/nothing.rb"}
|
269
|
+
blob = collector.get_blob(sha, file)
|
270
|
+
|
271
|
+
it {blob.should == nil}
|
272
|
+
end
|
273
|
+
|
274
|
+
context "with deleted file" do
|
275
|
+
file = {:file => "spec/collector_spec.rb"}
|
276
|
+
blob = collector.get_blob(sha, file)
|
277
|
+
|
278
|
+
it {blob.instance_of?(Grit::Blob).should be_true}
|
279
|
+
it {blob.name.should == file[:file].split(File::Separator).last}
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "#process_blob" do
|
284
|
+
sha = "695b487432e8a1ede765b4e3efda088ab87a77f8" # Commit within repository
|
285
|
+
|
286
|
+
context "with status (delete) blob" do
|
287
|
+
file = {:file => "spec/collector_spec.rb",
|
288
|
+
:additions => 0,
|
289
|
+
:deletions => 6,
|
290
|
+
:status => "delete"}
|
291
|
+
|
292
|
+
blob = collector.get_blob(sha, file)
|
293
|
+
data = Hash.new(0)
|
294
|
+
data[:files] = []
|
295
|
+
data = collector.process_blob(data, blob, file)
|
296
|
+
data_file = data[:files].first
|
297
|
+
|
298
|
+
it {data[:additions].should == file[:additions]}
|
299
|
+
it {data[:deletions].should == file[:deletions]}
|
300
|
+
|
301
|
+
it {data_file[:name].should == file[:file]}
|
302
|
+
it {data_file[:additions].should == file[:additions]}
|
303
|
+
it {data_file[:deletions].should == file[:deletions]}
|
304
|
+
it {data_file[:status].should == file[:status]}
|
305
|
+
it {data_file[:binary].should == false}
|
306
|
+
it {data_file[:image].should == false}
|
307
|
+
it {data_file[:vendored].should == false}
|
308
|
+
it {data_file[:generated].should == false}
|
309
|
+
it {data_file[:language].should == "Ruby"}
|
310
|
+
end
|
311
|
+
|
312
|
+
context "with invalid language blob" do
|
313
|
+
file = {:file => "Gemfile.lock",
|
314
|
+
:additions => 33,
|
315
|
+
:deletions => 11,
|
316
|
+
:status => nil}
|
317
|
+
|
318
|
+
blob = collector.get_blob(sha, file)
|
319
|
+
data = Hash.new(0)
|
320
|
+
data[:files] = []
|
321
|
+
data = collector.process_blob(data, blob, file)
|
322
|
+
data_file = data[:files].first
|
323
|
+
|
324
|
+
it {data[:additions].should == file[:additions]}
|
325
|
+
it {data[:deletions].should == file[:deletions]}
|
326
|
+
|
327
|
+
it {data_file[:name].should == file[:file]}
|
328
|
+
it {data_file[:additions].should == file[:additions]}
|
329
|
+
it {data_file[:deletions].should == file[:deletions]}
|
330
|
+
it {data_file[:status].should == nil}
|
331
|
+
it {data_file[:binary].should == false}
|
332
|
+
it {data_file[:image].should == false}
|
333
|
+
it {data_file[:vendored].should == false}
|
334
|
+
it {data_file[:generated].should == true}
|
335
|
+
it {data_file[:language].should == "Unknown"}
|
336
|
+
end
|
337
|
+
|
338
|
+
context "with valid language blob" do
|
339
|
+
file = {:file => "README.md",
|
340
|
+
:additions => 7,
|
341
|
+
:deletions => 3,
|
342
|
+
:status => nil}
|
343
|
+
|
344
|
+
blob = collector.get_blob(sha, file)
|
345
|
+
data = Hash.new(0)
|
346
|
+
data[:files] = []
|
347
|
+
data = collector.process_blob(data, blob, file)
|
348
|
+
data_file = data[:files].first
|
349
|
+
|
350
|
+
it {data[:additions].should == file[:additions]}
|
351
|
+
it {data[:deletions].should == file[:deletions]}
|
352
|
+
|
353
|
+
it {data_file[:name].should == file[:file]}
|
354
|
+
it {data_file[:additions].should == file[:additions]}
|
355
|
+
it {data_file[:deletions].should == file[:deletions]}
|
356
|
+
it {data_file[:status].should == nil}
|
357
|
+
it {data_file[:binary].should == false}
|
358
|
+
it {data_file[:image].should == false}
|
359
|
+
it {data_file[:vendored].should == false}
|
360
|
+
it {data_file[:generated].should == false}
|
361
|
+
it {data_file[:language].should == "Markdown"}
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
end
|
@@ -0,0 +1,238 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
include GitStatistics
|
3
|
+
|
4
|
+
describe Commits do
|
5
|
+
collector = Collector.new(false)
|
6
|
+
|
7
|
+
describe "#author_top_n_type" do
|
8
|
+
context "with valid data" do
|
9
|
+
commits = Commits.new
|
10
|
+
commits.load(fixture("multiple_authors.json"))
|
11
|
+
|
12
|
+
commits.calculate_statistics(false, false)
|
13
|
+
stats = commits.author_top_n_type(:deletions)
|
14
|
+
|
15
|
+
# Check stats for first author
|
16
|
+
author_1 = "John Smith"
|
17
|
+
it {stats.has_key?(author_1).should be_true}
|
18
|
+
it {stats[author_1][:commits].should == 1}
|
19
|
+
it {stats[author_1][:additions].should == 64}
|
20
|
+
it {stats[author_1][:deletions].should == 16}
|
21
|
+
|
22
|
+
it {stats[author_1][:languages][:Ruby][:additions].should == 64}
|
23
|
+
it {stats[author_1][:languages][:Ruby][:deletions].should == 16}
|
24
|
+
|
25
|
+
# Check stats for second author
|
26
|
+
author_2 = "Kevin Jalbert"
|
27
|
+
it {stats.has_key?(author_2).should be_true}
|
28
|
+
it {stats[author_2][:commits].should == 1}
|
29
|
+
it {stats[author_2][:additions].should == 73}
|
30
|
+
it {stats[author_2][:deletions].should == 0}
|
31
|
+
it {stats[author_2][:create].should == 2}
|
32
|
+
|
33
|
+
it {stats[author_2][:languages][:Markdown][:additions].should == 11}
|
34
|
+
it {stats[author_2][:languages][:Markdown][:deletions].should == 0}
|
35
|
+
it {stats[author_2][:languages][:Markdown][:create].should== 1}
|
36
|
+
it {stats[author_2][:languages][:Ruby][:additions].should == 62}
|
37
|
+
it {stats[author_2][:languages][:Ruby][:deletions].should == 0}
|
38
|
+
it {stats[author_2][:languages][:Ruby][:create].should == 1}
|
39
|
+
end
|
40
|
+
|
41
|
+
context "with invalid type" do
|
42
|
+
commits = Commits.new
|
43
|
+
commits.load(fixture("multiple_authors.json"))
|
44
|
+
|
45
|
+
commits.calculate_statistics(false, false)
|
46
|
+
stats = commits.author_top_n_type(:wrong)
|
47
|
+
|
48
|
+
it {stats.should == nil}
|
49
|
+
end
|
50
|
+
|
51
|
+
context "with invalid data" do
|
52
|
+
commits = Commits.new
|
53
|
+
|
54
|
+
commits.calculate_statistics(false, false)
|
55
|
+
stats = commits.author_top_n_type(:deletions)
|
56
|
+
|
57
|
+
it {stats.should == nil}
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#calculate_statistics" do
|
62
|
+
context "with email" do
|
63
|
+
commits = Commits.new
|
64
|
+
commits.load(fixture("single_author_pretty.json"))
|
65
|
+
|
66
|
+
commits.calculate_statistics(true, false)
|
67
|
+
stats = commits.author_top_n_type(:commits)
|
68
|
+
|
69
|
+
author = "kevin.j.jalbert@gmail.com"
|
70
|
+
it {stats.has_key?(author).should be_true}
|
71
|
+
it {stats[author][:commits].should == 1}
|
72
|
+
it {stats[author][:additions].should == 73}
|
73
|
+
it {stats[author][:deletions].should == 0}
|
74
|
+
it {stats[author][:create].should == 2}
|
75
|
+
|
76
|
+
it {stats[author][:languages][:Markdown][:additions].should == 11}
|
77
|
+
it {stats[author][:languages][:Markdown][:deletions].should == 0}
|
78
|
+
it {stats[author][:languages][:Ruby][:additions].should == 62}
|
79
|
+
it {stats[author][:languages][:Ruby][:deletions].should == 0}
|
80
|
+
it {stats[author][:languages][:Ruby][:create].should == 1}
|
81
|
+
end
|
82
|
+
|
83
|
+
context "with merge" do
|
84
|
+
commits = Commits.new
|
85
|
+
commits.load(fixture("single_author_pretty.json"))
|
86
|
+
|
87
|
+
commits.calculate_statistics(false, true)
|
88
|
+
stats = commits.author_top_n_type(:commits)
|
89
|
+
|
90
|
+
author = "Kevin Jalbert"
|
91
|
+
it {stats.has_key?(author).should be_true}
|
92
|
+
it {stats[author][:commits].should == 2}
|
93
|
+
it {stats[author][:additions].should == 153}
|
94
|
+
it {stats[author][:deletions].should == 5}
|
95
|
+
it {stats[author][:create].should == 3}
|
96
|
+
it {stats[author][:merges].should == 1}
|
97
|
+
|
98
|
+
it {stats[author][:languages][:Markdown][:additions].should == 18}
|
99
|
+
it {stats[author][:languages][:Markdown][:deletions].should == 1}
|
100
|
+
it {stats[author][:languages][:Ruby][:additions].should == 135}
|
101
|
+
it {stats[author][:languages][:Ruby][:deletions].should == 4}
|
102
|
+
it {stats[author][:languages][:Ruby][:create].should == 2}
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#add_language_stats" do
|
107
|
+
file = {:additions => 10,
|
108
|
+
:deletions => 5}
|
109
|
+
|
110
|
+
context "with file language" do
|
111
|
+
commits = Commits.new
|
112
|
+
data = Hash.new(0)
|
113
|
+
data[:languages] = {}
|
114
|
+
|
115
|
+
file[:language] = "Ruby"
|
116
|
+
|
117
|
+
data = commits.add_language_stats(data, file)
|
118
|
+
|
119
|
+
it {data[:languages][:Ruby][:additions].should == 10}
|
120
|
+
it {data[:languages][:Ruby][:deletions].should == 5}
|
121
|
+
end
|
122
|
+
|
123
|
+
context "with multiple files" do
|
124
|
+
commits = Commits.new
|
125
|
+
data = Hash.new(0)
|
126
|
+
data[:languages] = {}
|
127
|
+
|
128
|
+
# First file is "Ruby"
|
129
|
+
file[:language] = "Ruby"
|
130
|
+
data = commits.add_language_stats(data, file)
|
131
|
+
|
132
|
+
# Second file is "Java"
|
133
|
+
file[:language] = "Java"
|
134
|
+
data = commits.add_language_stats(data, file)
|
135
|
+
|
136
|
+
# Third file is "Ruby"
|
137
|
+
file[:language] = "Ruby"
|
138
|
+
data = commits.add_language_stats(data, file)
|
139
|
+
|
140
|
+
it {data[:languages][:Ruby][:additions].should == 20}
|
141
|
+
it {data[:languages][:Ruby][:deletions].should == 10}
|
142
|
+
it {data[:languages][:Java][:additions].should == 10}
|
143
|
+
it {data[:languages][:Java][:deletions].should == 5}
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
describe "#add_commit_stats" do
|
148
|
+
commit = {:additions => 10,
|
149
|
+
:deletions => 5,
|
150
|
+
:merge => false}
|
151
|
+
|
152
|
+
context "with valid commit" do
|
153
|
+
commits = Commits.new
|
154
|
+
data = Hash.new(0)
|
155
|
+
|
156
|
+
data = commits.add_commit_stats(data, commit)
|
157
|
+
|
158
|
+
it {data[:commits].should == 1}
|
159
|
+
it {data[:additions].should == 10}
|
160
|
+
it {data[:deletions].should == 5}
|
161
|
+
it {data[:merges].should == 0}
|
162
|
+
end
|
163
|
+
|
164
|
+
context "with multiple commits" do
|
165
|
+
commits = Commits.new
|
166
|
+
data = Hash.new(0)
|
167
|
+
|
168
|
+
data = commits.add_commit_stats(data, commit)
|
169
|
+
|
170
|
+
# Second commit has merge status
|
171
|
+
commit[:merge] = true
|
172
|
+
|
173
|
+
data = commits.add_commit_stats(data, commit)
|
174
|
+
|
175
|
+
it {data[:commits].should == 2}
|
176
|
+
it {data[:additions].should == 20}
|
177
|
+
it {data[:deletions].should == 10}
|
178
|
+
it {data[:merges].should == 1}
|
179
|
+
end
|
180
|
+
|
181
|
+
context "with commit that has file status changes" do
|
182
|
+
commits = Commits.new
|
183
|
+
data = Hash.new(0)
|
184
|
+
commit[:create] = 1
|
185
|
+
commit[:delete] = 2
|
186
|
+
commit[:rename] = 3
|
187
|
+
commit[:copy] = 4
|
188
|
+
|
189
|
+
data = commits.add_commit_stats(data, commit)
|
190
|
+
|
191
|
+
it {data[:commits].should == 1}
|
192
|
+
it {data[:additions].should == 10}
|
193
|
+
it {data[:deletions].should == 5}
|
194
|
+
it {data[:create].should == 1}
|
195
|
+
it {data[:delete].should == 2}
|
196
|
+
it {data[:rename].should == 3}
|
197
|
+
it {data[:copy].should == 4}
|
198
|
+
end
|
199
|
+
|
200
|
+
context "with merge commit" do
|
201
|
+
commits = Commits.new
|
202
|
+
data = Hash.new(0)
|
203
|
+
commit[:merge] = true
|
204
|
+
|
205
|
+
data = commits.add_commit_stats(data, commit)
|
206
|
+
|
207
|
+
it {data[:commits].should == 1}
|
208
|
+
it {data[:additions].should == 10}
|
209
|
+
it {data[:deletions].should == 5}
|
210
|
+
it {data[:merges].should == 1}
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "#save and #load" do
|
215
|
+
context "with pretty" do
|
216
|
+
commits = Commits.new
|
217
|
+
commits.load(fixture("single_author_pretty.json"))
|
218
|
+
commits.save("tmp.json", true)
|
219
|
+
|
220
|
+
same = FileUtils.compare_file("tmp.json", fixture("single_author_pretty.json"))
|
221
|
+
FileUtils.remove_file("tmp.json")
|
222
|
+
|
223
|
+
it {same.should be_true}
|
224
|
+
end
|
225
|
+
|
226
|
+
context "with no pretty" do
|
227
|
+
commits = Commits.new
|
228
|
+
commits.load(fixture("multiple_authors.json"))
|
229
|
+
commits.save("tmp.json", false)
|
230
|
+
|
231
|
+
same = FileUtils.compare_file("tmp.json", fixture("multiple_authors.json"))
|
232
|
+
FileUtils.remove_file("tmp.json")
|
233
|
+
|
234
|
+
it {same.should be_true}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
45 1 dir/README
|
2
|
+
6 5 dir/lib/{old_dir => new_dir}/copy_file.rb
|
3
|
+
0 0 dir/lib/rename/{old_file.rb => new_file.rb}
|
4
|
+
0 127 dir/lib/delete_file.rb
|
5
|
+
60 0 dir/lib/create_file.rb
|
6
|
+
copy dir/lib/{old_dir => new_dir}/copy_file.rb (65%)
|
7
|
+
rename dir/lib/rename/{old_file.rb => new_file.rb} (100%)
|
8
|
+
delete mode 100644 dir/lib/delete_file.rb
|
9
|
+
create mode 100644 dir/lib/create_file.rb
|
@@ -0,0 +1 @@
|
|
1
|
+
111111aa111a11111a11aa11aaaa11a111111a11,Test Author,author@test.com,2011-01-11 11:11:11 +0000,22bbbb2
|
@@ -0,0 +1 @@
|
|
1
|
+
111111aa111a11111a11aa11aaaa11a111111a11,Test Author,author@test.com,2011-01-11 11:11:11 +0000,
|
@@ -0,0 +1 @@
|
|
1
|
+
111111aa111a11111a11aa11aaaa11a111111a11,Test Author,author@test.com,2011-01-11 11:11:11 +0000,22bbbb2 33cccc3
|
@@ -0,0 +1 @@
|
|
1
|
+
* master
|
@@ -0,0 +1,4 @@
|
|
1
|
+
All authors(2) sorted by commits
|
2
|
+
----------------------------------------------------------------------------------------------------------------
|
3
|
+
Name/Email | Language | Commits | Additions | Deletions | Creates | Deletes | Renames | Copies | Merges |
|
4
|
+
----------------------------------------------------------------------------------------------------------------
|
@@ -0,0 +1 @@
|
|
1
|
+
{"0e82e507e5b64a1140623c702015b97b1b3f7f81":{"author":"Kevin Jalbert","author_email":"kevin.j.jalbert@gmail.com","time":"2012-04-04 13:46:56 -0400","files":[{"name":"README.md","additions":11,"deletions":0,"status":"create","binary":false,"image":false,"vendored":false,"generated":false,"language":"Markdown"},{"name":"git_statistics.rb","additions":62,"deletions":0,"status":"create","binary":false,"image":false,"vendored":false,"generated":false,"language":"Ruby"}],"merge":false,"create":2,"additions":73,"deletions":0},"fe947ea47b3d6240f2bb103ff51636038b3bb1d7":{"author":"John Smith","author_email":"john.smith@sample.com","time":"2012-04-04 19:22:04 -0400","files":[{"name":"git_statistics.rb","additions":64,"deletions":16,"status":null,"binary":false,"image":false,"vendored":false,"generated":false,"language":"Ruby"}],"merge":false,"additions":64,"deletions":16},"354e8a3795470d75388549d7326d9c12f6e0bf1a":{"author":"Kevin Jalbert","author_email":"kevin.j.jalbert@gmail.com","time":"2012-04-04 23:50:04 -0400","files":[{"name":"README.md","additions":7,"deletions":1,"status":null,"binary":false,"image":false,"vendored":false,"generated":false,"language":"Markdown"},{"name":"commits.rb","additions":64,"deletions":0,"status":"create","binary":false,"image":false,"vendored":false,"generated":false,"language":"Ruby"},{"name":"git_statistics.rb","additions":9,"deletions":4,"status":null,"binary":false,"image":false,"vendored":false,"generated":false,"language":"Ruby"}],"merge":true,"additions":80,"deletions":5,"create":1}}
|