git_statistics 0.3.0 → 0.4.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/.gitignore +6 -0
- data/CHANGELOG.md +1 -0
- data/lib/git_statistics.rb +22 -19
- data/lib/git_statistics/collector.rb +11 -4
- data/lib/git_statistics/commits.rb +64 -24
- data/lib/git_statistics/results.rb +4 -4
- data/lib/git_statistics/utilities.rb +13 -2
- data/lib/git_statistics/version.rb +1 -1
- data/spec/collector_spec.rb +101 -114
- data/spec/commits_spec.rb +222 -171
- data/spec/results_spec.rb +113 -89
- data/spec/spec_helper.rb +6 -0
- data/spec/utilities_spec.rb +97 -55
- metadata +2 -2
data/spec/results_spec.rb
CHANGED
@@ -2,82 +2,111 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
2
2
|
include GitStatistics
|
3
3
|
|
4
4
|
describe Results do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
commits.
|
12
|
-
|
13
|
-
|
5
|
+
let(:verbose) {false}
|
6
|
+
let(:limit) {100}
|
7
|
+
let(:fresh) {true}
|
8
|
+
let(:pretty) {false}
|
9
|
+
let(:collector) {Collector.new(verbose, limit, fresh, pretty)}
|
10
|
+
|
11
|
+
let(:commits) {collector.commits}
|
12
|
+
|
13
|
+
let(:fixture_file) {"multiple_authors.json"}
|
14
|
+
let(:save_file) {collector.commits_path + "0.json"}
|
15
|
+
let(:email) {false}
|
16
|
+
let(:merge) {false}
|
17
|
+
let(:sort) {:commits}
|
18
|
+
let(:top_n) {0}
|
19
|
+
|
20
|
+
let(:results) {
|
21
|
+
setup_commits(commits, fixture_file, save_file, pretty)
|
22
|
+
commits.calculate_statistics(email, merge)
|
23
|
+
commits.author_top_n_type(sort)
|
24
|
+
results = Results.new(commits)
|
25
|
+
}
|
26
|
+
|
27
|
+
let(:config) {
|
28
|
+
results.prepare_result_summary(sort, email, top_n)
|
29
|
+
}
|
14
30
|
|
15
31
|
describe "#prepare_result_summary" do
|
16
|
-
|
17
32
|
context "with email and sorting" do
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
33
|
+
context "on first author" do
|
34
|
+
let(:data) {config[:data]}
|
35
|
+
author = "Kevin Jalbert"
|
36
|
+
subject {data[author]}
|
37
|
+
|
38
|
+
it {data.has_key?(author).should be_true}
|
39
|
+
|
40
|
+
it {subject[:commits].should == 1}
|
41
|
+
it {subject[:additions].should == 73}
|
42
|
+
it {subject[:deletions].should == 0}
|
43
|
+
it {subject[:create].should == 2}
|
44
|
+
|
45
|
+
it {subject[:languages][:Ruby][:additions].should == 62}
|
46
|
+
it {subject[:languages][:Ruby][:deletions].should == 0}
|
47
|
+
it {subject[:languages][:Ruby][:create].should == 1}
|
48
|
+
it {subject[:languages][:Markdown][:additions].should == 11}
|
49
|
+
it {subject[:languages][:Markdown][:deletions].should == 0}
|
50
|
+
it {subject[:languages][:Markdown][:create].should == 1}
|
51
|
+
end
|
52
|
+
|
53
|
+
context "on second author" do
|
54
|
+
let(:data) {config[:data]}
|
55
|
+
author = "John Smith"
|
56
|
+
subject {data[author]}
|
57
|
+
|
58
|
+
it {data.has_key?(author).should be_true}
|
59
|
+
it {subject[:commits].should == 1}
|
60
|
+
it {subject[:additions].should == 64}
|
61
|
+
it {subject[:deletions].should == 16}
|
62
|
+
|
63
|
+
it {subject[:languages][:Ruby][:additions].should == 64}
|
64
|
+
it {subject[:languages][:Ruby][:deletions].should == 16}
|
65
|
+
end
|
45
66
|
|
46
67
|
it {config[:sort].should == sort}
|
47
68
|
it {config[:email].should == email}
|
48
|
-
it {config[:top_n].should ==
|
69
|
+
it {config[:top_n].should == top_n}
|
49
70
|
it {config[:author_length].should == 17}
|
50
71
|
it {config[:language_length].should == 8}
|
51
72
|
end
|
52
73
|
|
53
74
|
context "with negative top_n" do
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
75
|
+
let(:top_n) {-1}
|
76
|
+
|
77
|
+
context "on first author" do
|
78
|
+
let(:data) {config[:data]}
|
79
|
+
author = "Kevin Jalbert"
|
80
|
+
subject {data[author]}
|
81
|
+
|
82
|
+
it {data.has_key?(author).should be_true}
|
83
|
+
|
84
|
+
it {subject[:commits].should == 1}
|
85
|
+
it {subject[:additions].should == 73}
|
86
|
+
it {subject[:deletions].should == 0}
|
87
|
+
it {subject[:create].should == 2}
|
88
|
+
|
89
|
+
it {subject[:languages][:Ruby][:additions].should == 62}
|
90
|
+
it {subject[:languages][:Ruby][:deletions].should == 0}
|
91
|
+
it {subject[:languages][:Ruby][:create].should == 1}
|
92
|
+
it {subject[:languages][:Markdown][:additions].should == 11}
|
93
|
+
it {subject[:languages][:Markdown][:deletions].should == 0}
|
94
|
+
it {subject[:languages][:Markdown][:create].should == 1}
|
95
|
+
end
|
96
|
+
|
97
|
+
context "on second author" do
|
98
|
+
let(:data) {config[:data]}
|
99
|
+
author = "John Smith"
|
100
|
+
subject {data[author]}
|
101
|
+
|
102
|
+
it {data.has_key?(author).should be_true}
|
103
|
+
it {subject[:commits].should == 1}
|
104
|
+
it {subject[:additions].should == 64}
|
105
|
+
it {subject[:deletions].should == 16}
|
106
|
+
|
107
|
+
it {subject[:languages][:Ruby][:additions].should == 64}
|
108
|
+
it {subject[:languages][:Ruby][:deletions].should == 16}
|
109
|
+
end
|
81
110
|
|
82
111
|
it {config[:sort].should == sort}
|
83
112
|
it {config[:email].should == email}
|
@@ -87,30 +116,28 @@ describe Results do
|
|
87
116
|
end
|
88
117
|
|
89
118
|
context "with top_n that filters to one author" do
|
90
|
-
|
91
|
-
data
|
92
|
-
|
93
|
-
|
94
|
-
author_2 = "John Smith"
|
119
|
+
let(:top_n) {1}
|
120
|
+
let(:data) {config[:data]}
|
121
|
+
author = "Kevin Jalbert"
|
122
|
+
subject {data[author]}
|
95
123
|
|
96
|
-
it {data.has_key?(
|
97
|
-
it {data.has_key?(author_2).should be_false}
|
124
|
+
it {data.has_key?(author).should be_true}
|
98
125
|
|
99
|
-
it {
|
100
|
-
it {
|
101
|
-
it {
|
102
|
-
it {
|
126
|
+
it {subject[:commits].should == 1}
|
127
|
+
it {subject[:additions].should == 73}
|
128
|
+
it {subject[:deletions].should == 0}
|
129
|
+
it {subject[:create].should == 2}
|
103
130
|
|
104
|
-
it {
|
105
|
-
it {
|
106
|
-
it {
|
107
|
-
it {
|
108
|
-
it {
|
109
|
-
it {
|
131
|
+
it {subject[:languages][:Ruby][:additions].should == 62}
|
132
|
+
it {subject[:languages][:Ruby][:deletions].should == 0}
|
133
|
+
it {subject[:languages][:Ruby][:create].should == 1}
|
134
|
+
it {subject[:languages][:Markdown][:additions].should == 11}
|
135
|
+
it {subject[:languages][:Markdown][:deletions].should == 0}
|
136
|
+
it {subject[:languages][:Markdown][:create].should == 1}
|
110
137
|
|
111
138
|
it {config[:sort].should == sort}
|
112
139
|
it {config[:email].should == email}
|
113
|
-
it {config[:top_n].should ==
|
140
|
+
it {config[:top_n].should == top_n}
|
114
141
|
it {config[:author_length].should == 17}
|
115
142
|
it {config[:language_length].should == 8}
|
116
143
|
end
|
@@ -118,24 +145,21 @@ describe Results do
|
|
118
145
|
|
119
146
|
describe "#print_summary" do
|
120
147
|
context "with valid data" do
|
121
|
-
|
122
|
-
language_data = results.print_summary(sort, email)
|
148
|
+
let(:language_data) {results.print_summary(sort, email)}
|
123
149
|
it {language_data.should == fixture("summary_output.txt").read}
|
124
150
|
end
|
125
151
|
end
|
126
152
|
|
127
153
|
describe "#print_language_data" do
|
128
154
|
context "with valid data" do
|
129
|
-
|
130
|
-
language_data = results.print_language_data(config[:pattern], config[:data]["Kevin Jalbert"])
|
155
|
+
let(:language_data) {results.print_language_data(config[:pattern], config[:data]["Kevin Jalbert"])}
|
131
156
|
it {language_data.should == fixture("language_data_output.txt").read}
|
132
157
|
end
|
133
158
|
end
|
134
159
|
|
135
160
|
describe "#print_header" do
|
136
161
|
context "with valid data" do
|
137
|
-
|
138
|
-
header = results.print_header(config)
|
162
|
+
let(:header) {results.print_header(config)}
|
139
163
|
it {header.should == fixture("header_output.txt").read}
|
140
164
|
end
|
141
165
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -9,3 +9,9 @@ require File.dirname(__FILE__) + '/../lib/git_statistics/initialize.rb'
|
|
9
9
|
def fixture(file)
|
10
10
|
File.new(File.dirname(__FILE__) + '/fixtures/' + file, 'r')
|
11
11
|
end
|
12
|
+
|
13
|
+
def setup_commits(commits, file_load, file_save, pretty)
|
14
|
+
return if file_load == nil || file_save == nil
|
15
|
+
commits.load(fixture(file_load))
|
16
|
+
commits.save(file_save, pretty)
|
17
|
+
end
|
data/spec/utilities_spec.rb
CHANGED
@@ -4,62 +4,67 @@ include GitStatistics
|
|
4
4
|
describe Utilities do
|
5
5
|
|
6
6
|
describe "#get_repository" do
|
7
|
+
let(:repo) {Utilities.get_repository(dir)}
|
8
|
+
|
7
9
|
context "with root directory" do
|
8
|
-
|
10
|
+
let(:dir) {Dir.pwd} # git_statistics/
|
9
11
|
it {repo.instance_of?(Grit::Repo).should be_true}
|
10
12
|
end
|
11
13
|
|
12
14
|
context "with sub directory" do
|
13
|
-
|
15
|
+
let(:dir) {File.dirname(__FILE__)} # git_statistics/spec/
|
14
16
|
it {repo.instance_of?(Grit::Repo).should be_true}
|
15
17
|
end
|
16
18
|
|
17
|
-
context "not in a repository directory" do
|
18
|
-
|
19
|
+
context "when not in a repository directory" do
|
20
|
+
let(:dir) {Dir.pwd + "../"} # git_statistics/../
|
19
21
|
it {repo.should == nil}
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
describe "#find_longest_length" do
|
26
|
+
let(:max) {nil}
|
27
|
+
let(:results) {Utilities.find_longest_length(list, max)}
|
28
|
+
|
24
29
|
context "with empty list" do
|
25
|
-
|
30
|
+
let(:list) {[]}
|
26
31
|
it {results.should == nil}
|
27
32
|
end
|
28
33
|
|
29
34
|
context "with nil list" do
|
30
|
-
|
35
|
+
let(:list) {nil}
|
31
36
|
it {results.should == nil}
|
32
37
|
end
|
33
38
|
|
34
39
|
context "with preset minimum length" do
|
35
|
-
|
40
|
+
let(:list) {[]}
|
41
|
+
let(:max) {10}
|
36
42
|
it {results.should == 10}
|
37
43
|
end
|
38
44
|
|
39
45
|
context "with valid list" do
|
40
|
-
list
|
41
|
-
results = Utilities.find_longest_length(list)
|
46
|
+
let(:list) {["abc", "a", "ab"]}
|
42
47
|
it {results.should == 3}
|
43
48
|
end
|
44
49
|
|
45
50
|
context "with valid hash" do
|
46
|
-
list
|
47
|
-
results = Utilities.find_longest_length(list)
|
51
|
+
let(:list) {{"a" => "word_a", "ab" => "word_b", "abc" => "word_c"}}
|
48
52
|
it {results.should == 3}
|
49
53
|
end
|
50
54
|
end
|
51
55
|
|
52
56
|
describe "#unique_data_in_hash" do
|
53
|
-
type
|
57
|
+
let(:type) {:word}
|
58
|
+
let(:list) {Utilities.unique_data_in_hash(data, type)}
|
54
59
|
|
55
60
|
context "with valid type" do
|
56
|
-
data
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
61
|
+
let(:data) {
|
62
|
+
{:entry_a => {type => "test"},
|
63
|
+
:entry_b => {type => "a"},
|
64
|
+
:entry_c => {type => "a"},
|
65
|
+
:entry_d => {type => "is"},
|
66
|
+
:entry_e => {type => "test"}}
|
67
|
+
}
|
63
68
|
|
64
69
|
it {list.size.should == 3}
|
65
70
|
it {list.include?("is").should be_true}
|
@@ -68,102 +73,139 @@ describe Utilities do
|
|
68
73
|
end
|
69
74
|
|
70
75
|
context "with invalid type" do
|
71
|
-
data
|
72
|
-
|
73
|
-
|
74
|
-
|
76
|
+
let(:data) {
|
77
|
+
{:entry_a => {:wrong => "test"},
|
78
|
+
:entry_b => {:wrong => "is"}}
|
79
|
+
}
|
75
80
|
|
76
81
|
it {list.should == [nil]}
|
77
82
|
end
|
78
83
|
end
|
79
84
|
|
80
85
|
describe "#clean_string" do
|
86
|
+
let(:unclean) {" master "}
|
87
|
+
let(:clean) {Utilities.clean_string(unclean)}
|
88
|
+
|
81
89
|
context "with trailling spaces" do
|
82
|
-
unclean = " master "
|
83
|
-
clean = Utilities.clean_string(unclean)
|
84
90
|
it {clean.should == "master"}
|
85
91
|
end
|
86
92
|
end
|
87
93
|
|
88
94
|
describe "#split_old_new_file" do
|
95
|
+
let(:files) {Utilities.split_old_new_file(old, new)}
|
89
96
|
context "with a change in middle" do
|
90
|
-
old
|
91
|
-
new
|
92
|
-
files = Utilities.split_old_new_file(old, new)
|
93
|
-
it {files[:old_file].should == "lib/old_dir/file.rb"}
|
97
|
+
let(:old) {"lib/{old_dir"}
|
98
|
+
let(:new) {"new_dir}/file.rb"}
|
94
99
|
it {files[:new_file].should == "lib/new_dir/file.rb"}
|
95
100
|
end
|
96
101
|
|
97
102
|
context "with a change at beginning" do
|
98
|
-
old
|
99
|
-
new
|
100
|
-
files = Utilities.split_old_new_file(old, new)
|
103
|
+
let(:old) {"{src/dir/lib"}
|
104
|
+
let(:new) {"lib/dir}/file.rb"}
|
101
105
|
it {files[:old_file].should == "src/dir/lib/file.rb"}
|
102
106
|
it {files[:new_file].should == "lib/dir/file.rb"}
|
103
107
|
end
|
104
108
|
|
105
109
|
context "with a change at beginning, alternative" do
|
106
|
-
old
|
107
|
-
new
|
108
|
-
files = Utilities.split_old_new_file(old, new)
|
110
|
+
let(:old) {"src/{"}
|
111
|
+
let(:new) {"dir}/file.rb"}
|
109
112
|
it {files[:old_file].should == "src/file.rb"}
|
110
113
|
it {files[:new_file].should == "src/dir/file.rb"}
|
111
114
|
end
|
112
115
|
|
113
116
|
context "with a change at ending" do
|
114
|
-
old
|
115
|
-
new
|
116
|
-
files = Utilities.split_old_new_file(old, new)
|
117
|
+
let(:old) {"lib/dir/{old_file.rb"}
|
118
|
+
let(:new) {"new_file.rb}"}
|
117
119
|
it {files[:old_file].should == "lib/dir/old_file.rb"}
|
118
120
|
it {files[:new_file].should == "lib/dir/new_file.rb"}
|
119
121
|
end
|
120
122
|
|
121
123
|
context "with a simple complete change" do
|
122
|
-
old
|
123
|
-
new
|
124
|
-
files = Utilities.split_old_new_file(old, new)
|
124
|
+
let(:old) {"file.rb"}
|
125
|
+
let(:new) {"lib/dir/file.rb}"}
|
125
126
|
it {files[:old_file].should == "file.rb"}
|
126
127
|
it {files[:new_file].should == "lib/dir/file.rb"}
|
127
128
|
end
|
128
129
|
end
|
129
130
|
|
130
|
-
describe "find_blob_in_tree" do
|
131
|
-
|
132
|
-
sha
|
133
|
-
|
131
|
+
describe "#find_blob_in_tree" do
|
132
|
+
let(:sha) {"7d6c29f0ad5860d3238debbaaf696e361bf8c541"} # Commit within repository
|
133
|
+
let(:tree) {Utilities.get_repository(Dir.pwd).tree(sha)}
|
134
|
+
let(:file) {nil}
|
135
|
+
let(:blob) {Utilities.find_blob_in_tree(tree, file.split(File::Separator))}
|
134
136
|
|
135
137
|
context "blob on root tree" do
|
136
|
-
file
|
137
|
-
blob = Utilities.find_blob_in_tree(tree, file.split(File::Separator))
|
138
|
+
let(:file) {"Gemfile"}
|
138
139
|
it {blob.instance_of?(Grit::Blob).should be_true}
|
139
140
|
it {blob.name.should == file}
|
140
141
|
end
|
141
142
|
|
142
143
|
context "blob down tree" do
|
143
|
-
file
|
144
|
-
blob = Utilities.find_blob_in_tree(tree, file.split(File::Separator))
|
144
|
+
let(:file) {"lib/git_statistics/collector.rb"}
|
145
145
|
it {blob.instance_of?(Grit::Blob).should be_true}
|
146
146
|
it {blob.name.should == file.split(File::Separator).last}
|
147
147
|
end
|
148
148
|
|
149
149
|
context "file is nil" do
|
150
|
-
blob
|
150
|
+
let(:blob) {Utilities.find_blob_in_tree(tree, nil)}
|
151
151
|
it {blob.should == nil}
|
152
152
|
end
|
153
153
|
|
154
154
|
context "file is empty" do
|
155
|
-
|
155
|
+
let(:file) {""}
|
156
156
|
it {blob.should == nil}
|
157
157
|
end
|
158
158
|
|
159
159
|
context "file is submodule" do
|
160
|
-
sha
|
161
|
-
|
162
|
-
file = "Spoon-Knife"
|
163
|
-
blob = Utilities.find_blob_in_tree(tree, file.split(File::Separator))
|
160
|
+
let(:sha) {"1940ef1c613a04f855d3867b874a4267d3e2c011"}
|
161
|
+
let(:file) {"Spoon-Knife"}
|
164
162
|
it {blob.instance_of?(Grit::Submodule).should be_true}
|
165
163
|
it {blob.name.should == file}
|
166
164
|
end
|
167
165
|
end
|
168
166
|
|
167
|
+
describe "#get_number_of_files" do
|
168
|
+
let(:files) {Utilities.get_number_of_files(directory, pattern)}
|
169
|
+
let(:pattern) {/\d+\.json/}
|
170
|
+
let(:directory) {Dir.pwd + File::Separator + "tmp_dir_for_spec" + File::Separator}
|
171
|
+
|
172
|
+
before(:each) do
|
173
|
+
FileUtils.mkdir_p(directory)
|
174
|
+
end
|
175
|
+
|
176
|
+
after(:each) do
|
177
|
+
FileUtils.rmdir(directory)
|
178
|
+
end
|
179
|
+
|
180
|
+
context "with valid files" do
|
181
|
+
it do
|
182
|
+
FileUtils.touch(directory + "0.json")
|
183
|
+
FileUtils.touch(directory + "1.json")
|
184
|
+
FileUtils.touch(directory + "2.json")
|
185
|
+
files.should == 3
|
186
|
+
FileUtils.rm(directory + "0.json")
|
187
|
+
FileUtils.rm(directory + "1.json")
|
188
|
+
FileUtils.rm(directory + "2.json")
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
context "with invalid files" do
|
193
|
+
it do
|
194
|
+
FileUtils.touch(directory + "0.json")
|
195
|
+
FileUtils.touch(directory + "incorrect.json")
|
196
|
+
FileUtils.touch(directory + "1.json")
|
197
|
+
files.should == 2
|
198
|
+
FileUtils.rm(directory + "0.json")
|
199
|
+
FileUtils.rm(directory + "incorrect.json")
|
200
|
+
FileUtils.rm(directory + "1.json")
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
context "with no files" do
|
205
|
+
it do
|
206
|
+
files.should == 0
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
169
211
|
end
|