git_statistics 0.5.1 → 0.6.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/bin/git-statistics +2 -1
- data/bin/git_statistics +2 -1
- data/lib/git_statistics.rb +69 -21
- data/lib/git_statistics/branches.rb +35 -0
- data/lib/git_statistics/collector.rb +20 -45
- data/lib/git_statistics/commit_line_extractor.rb +8 -8
- data/lib/git_statistics/commits.rb +7 -4
- data/lib/git_statistics/formatters/console.rb +50 -47
- data/lib/git_statistics/initialize.rb +0 -3
- data/lib/git_statistics/log.rb +59 -0
- data/lib/git_statistics/pipe.rb +29 -0
- data/lib/git_statistics/utilities.rb +33 -23
- data/lib/git_statistics/version.rb +1 -1
- data/spec/branches_spec.rb +44 -0
- data/spec/collector_spec.rb +20 -41
- data/spec/commits_spec.rb +51 -47
- data/spec/formatters/console_spec.rb +25 -18
- data/spec/log_spec.rb +54 -0
- data/spec/pipe_spec.rb +59 -0
- data/spec/utilities_spec.rb +65 -63
- metadata +52 -9
- data/lib/git_statistics/core_ext/string.rb +0 -11
@@ -1,12 +1,9 @@
|
|
1
1
|
require 'json'
|
2
|
-
require 'trollop'
|
3
2
|
require 'grit'
|
4
3
|
require 'linguist'
|
5
|
-
require 'os'
|
6
4
|
require 'pathname'
|
7
5
|
|
8
6
|
# Must be required before all other files
|
9
|
-
require 'git_statistics/core_ext/string'
|
10
7
|
require 'git_statistics/blob'
|
11
8
|
require 'git_statistics/regex_matcher'
|
12
9
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'logger'
|
2
|
+
require 'singleton'
|
3
|
+
|
4
|
+
module GitStatistics
|
5
|
+
class Log
|
6
|
+
include Singleton
|
7
|
+
|
8
|
+
attr_accessor :logger, :base_directory, :debugging
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@base_directory = File.expand_path("../..", __FILE__) + "/"
|
12
|
+
@debugging = false
|
13
|
+
@logger = Logger.new(STDOUT)
|
14
|
+
@logger.level = Logger::ERROR
|
15
|
+
@logger.formatter = proc do |sev, datetime, progname, msg|
|
16
|
+
"#{msg}\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.use_debug
|
21
|
+
instance.debugging = true
|
22
|
+
instance.logger.formatter = proc do |sev, datetime, progname, msg|
|
23
|
+
"#{sev} [#{progname}]: #{msg}\n"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Determine the file, method, line number of the caller
|
28
|
+
def self.parse_caller(message)
|
29
|
+
if /^(?<file>.+?):(?<line>\d+)(?::in `(?<method>.*)')?/ =~ message
|
30
|
+
file = Regexp.last_match[:file]
|
31
|
+
line = Regexp.last_match[:line]
|
32
|
+
method = Regexp.last_match[:method]
|
33
|
+
"#{file.sub(instance.base_directory, "")}:#{line}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.method_missing(method, *args, &blk)
|
38
|
+
if valid_method? method
|
39
|
+
instance.logger.progname = parse_caller(caller(1).first) if instance.debugging
|
40
|
+
instance.logger.send(method, *args, &blk)
|
41
|
+
else
|
42
|
+
super
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.respond_to_missing?(method, include_all=false)
|
47
|
+
if valid_method? method
|
48
|
+
true
|
49
|
+
else
|
50
|
+
super
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.valid_method?(method)
|
55
|
+
instance.logger.respond_to? method
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module GitStatistics
|
2
|
+
class Pipe
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(command)
|
6
|
+
@command = command
|
7
|
+
end
|
8
|
+
|
9
|
+
def command
|
10
|
+
@command.dup.gsub(/\A\|/i, '')
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
lines.each(&block)
|
15
|
+
end
|
16
|
+
|
17
|
+
def empty?
|
18
|
+
lines.empty?
|
19
|
+
end
|
20
|
+
|
21
|
+
def lines
|
22
|
+
io.map { |line| line.strip.force_encoding("iso-8859-1").encode("utf-8") }
|
23
|
+
end
|
24
|
+
|
25
|
+
def io
|
26
|
+
open("|#{command} 2>/dev/null")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -1,17 +1,18 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
1
3
|
module GitStatistics
|
2
4
|
module Utilities
|
5
|
+
|
6
|
+
class NotInRepository < StandardError; end
|
7
|
+
|
3
8
|
def self.get_repository(path = Dir.pwd)
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
rescue
|
12
|
-
directory = directory.parent
|
13
|
-
end
|
14
|
-
end
|
9
|
+
ascender = Pathname.new(path).to_enum(:ascend)
|
10
|
+
repo_path = ascender.detect { |path| (path + '.git').exist? }
|
11
|
+
raise NotInRepository unless repo_path
|
12
|
+
Grit::Repo.new(repo_path.to_s)
|
13
|
+
rescue NotInRepository
|
14
|
+
Log.error "You must be within a Git project to run git-statistics."
|
15
|
+
exit 0
|
15
16
|
end
|
16
17
|
|
17
18
|
def self.max_length_in_list(list, max = nil)
|
@@ -22,10 +23,6 @@ module GitStatistics
|
|
22
23
|
max
|
23
24
|
end
|
24
25
|
|
25
|
-
def self.clean_string(string)
|
26
|
-
string.strip.force_encoding("iso-8859-1").encode("utf-8")
|
27
|
-
end
|
28
|
-
|
29
26
|
def self.split_old_new_file(old, new)
|
30
27
|
# Split the old and new chunks up (separted by the =>)
|
31
28
|
split_old = old.split('{')
|
@@ -84,11 +81,26 @@ module GitStatistics
|
|
84
81
|
end
|
85
82
|
|
86
83
|
def self.get_modified_time(file)
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
time_at(
|
84
|
+
if os == :windows
|
85
|
+
raise "`stat` is not supported on the Windows operating system"
|
86
|
+
end
|
87
|
+
flags = os == :mac ? "-f %m" : "-c %Y"
|
88
|
+
time_at("stat #{flags} #{file}")
|
89
|
+
end
|
90
|
+
|
91
|
+
def os
|
92
|
+
case RbConfig::CONFIG['host_os']
|
93
|
+
when /mswin|msys|mingw|cygwin|bccwin|wince|emc/
|
94
|
+
:windows
|
95
|
+
when /darwin|mac os/
|
96
|
+
:mac
|
97
|
+
when /linux/
|
98
|
+
:linux
|
99
|
+
when /solaris|bsd/
|
100
|
+
:unix
|
101
|
+
else
|
102
|
+
:unknown
|
103
|
+
end
|
92
104
|
end
|
93
105
|
|
94
106
|
def self.time_at(cmd)
|
@@ -96,9 +108,7 @@ module GitStatistics
|
|
96
108
|
end
|
97
109
|
|
98
110
|
def self.number_of_matching_files(directory, pattern)
|
99
|
-
Dir.entries(directory)
|
100
|
-
.select { |file| file =~ pattern }
|
101
|
-
.size
|
111
|
+
Dir.entries(directory).grep(pattern).size
|
102
112
|
rescue SystemCallError
|
103
113
|
warn "No such directory #{File.expand_path(directory)}"
|
104
114
|
0
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
include GitStatistics
|
3
|
+
|
4
|
+
describe Branches do
|
5
|
+
subject { described_class }
|
6
|
+
|
7
|
+
before do
|
8
|
+
subject.stub(:pipe) { fixture(branches) }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "with many branches" do
|
12
|
+
let(:branches) {"git_many_branches.txt"}
|
13
|
+
its(:all) { should have(2).items }
|
14
|
+
its(:all) { should include "issue_2" }
|
15
|
+
its(:all) { should include "master" }
|
16
|
+
its(:current) { should == "issue_2" }
|
17
|
+
its(:detached?) { should be_false }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "with zero branches" do
|
21
|
+
let(:branches) {"git_zero_branches.txt"}
|
22
|
+
its(:all) { should have(1).items }
|
23
|
+
its(:all) { should include "master" }
|
24
|
+
its(:current) { should == "master" }
|
25
|
+
its(:detached?) { should be_false }
|
26
|
+
end
|
27
|
+
|
28
|
+
context "with many branches in detached state" do
|
29
|
+
let(:branches) {"git_many_branches_detached_state.txt"}
|
30
|
+
its(:all) { should have(2).items }
|
31
|
+
its(:all) { should include "issue_2" }
|
32
|
+
its(:all) { should include "master" }
|
33
|
+
its(:current) { should == "(none)" }
|
34
|
+
its(:detached?) { should be_true }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "with zero branches in detached state" do
|
38
|
+
let(:branches) {"git_zero_branches_detached_state.txt"}
|
39
|
+
its(:all) { should have(1).items }
|
40
|
+
its(:all) { should include "master" }
|
41
|
+
its(:current) { should == "(none)" }
|
42
|
+
its(:detached?) { should be_true }
|
43
|
+
end
|
44
|
+
end
|
data/spec/collector_spec.rb
CHANGED
@@ -2,17 +2,14 @@ require 'spec_helper'
|
|
2
2
|
include GitStatistics
|
3
3
|
|
4
4
|
describe Collector do
|
5
|
-
let(:verbose) {false}
|
6
5
|
let(:limit) {100}
|
7
6
|
let(:fresh) {true}
|
8
7
|
let(:pretty) {false}
|
9
|
-
let(:collector) {Collector.new(
|
8
|
+
let(:collector) {Collector.new(limit, fresh, pretty)}
|
10
9
|
|
11
10
|
# Create buffer which is an array of cleaned lines
|
12
11
|
let(:buffer) {
|
13
|
-
fixture(fixture_file).
|
14
|
-
line.clean_for_authors
|
15
|
-
end
|
12
|
+
fixture(fixture_file).lines
|
16
13
|
}
|
17
14
|
|
18
15
|
describe "#collect" do
|
@@ -83,26 +80,8 @@ describe Collector do
|
|
83
80
|
end
|
84
81
|
end
|
85
82
|
|
86
|
-
describe "#collect_branches" do
|
87
|
-
let(:branches) {collector.collect_branches(fixture(fixture_file))}
|
88
|
-
|
89
|
-
context "with many branches" do
|
90
|
-
let(:fixture_file) {"git_many_branches.txt"}
|
91
|
-
it {branches.size.should == 2}
|
92
|
-
it {branches[0].should == "issue_2"}
|
93
|
-
it {branches[1].should == "master"}
|
94
|
-
end
|
95
|
-
|
96
|
-
context "with zero branches" do
|
97
|
-
let(:fixture_file) {"git_zero_branches.txt"}
|
98
|
-
it {branches.size.should == 1}
|
99
|
-
it {branches[0].should == "master"}
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
83
|
describe "#acquire_commit_data" do
|
104
|
-
let(:
|
105
|
-
let(:data) {collector.acquire_commit_data(input)}
|
84
|
+
let(:data) {collector.acquire_commit_data(buffer.first)}
|
106
85
|
|
107
86
|
context "no parent, first commit" do
|
108
87
|
let(:fixture_file) {"commit_buffer_information_first.txt"}
|
@@ -231,38 +210,38 @@ describe Collector do
|
|
231
210
|
end
|
232
211
|
|
233
212
|
describe "#fall_back_collect_commit" do
|
234
|
-
|
213
|
+
subject { collector.fall_back_collect_commit(sha) }
|
235
214
|
context "with valid sha" do
|
236
|
-
let(:fixture_file) {"commit_buffer_whole.txt"}
|
237
|
-
let(:sha) {"260bc61e2c42930d91f3503c5849b0a2351275cf"}
|
238
|
-
it {
|
215
|
+
let(:fixture_file) { "commit_buffer_whole.txt" }
|
216
|
+
let(:sha) { "260bc61e2c42930d91f3503c5849b0a2351275cf" }
|
217
|
+
it { should == buffer }
|
239
218
|
end
|
240
219
|
|
241
220
|
context "with invalid sha" do
|
242
|
-
let(:sha) {"111111aa111a11111a11aa11aaaa11a111111a11"}
|
243
|
-
it {
|
221
|
+
let(:sha) { "111111aa111a11111a11aa11aaaa11a111111a11" }
|
222
|
+
it { should be_empty }
|
244
223
|
end
|
245
224
|
end
|
246
225
|
|
247
226
|
describe "#get_blob" do
|
248
|
-
let(:sha) {"695b487432e8a1ede765b4e3efda088ab87a77f8"} # Commit within repository
|
249
|
-
|
227
|
+
let(:sha) { "695b487432e8a1ede765b4e3efda088ab87a77f8" } # Commit within repository
|
228
|
+
subject { collector.get_blob(sha, file) }
|
250
229
|
|
251
230
|
context "with valid blob" do
|
252
231
|
let(:file) {{:file => "Gemfile.lock"}}
|
253
|
-
it {
|
254
|
-
|
255
|
-
end
|
256
|
-
|
257
|
-
context "with invalid blob" do
|
258
|
-
let(:file) {{:file => "dir/nothing.rb"}}
|
259
|
-
it {blob.should.nil?}
|
232
|
+
it { should be_a Grit::Blob }
|
233
|
+
its(:name) { should == File.basename(file[:file]) }
|
260
234
|
end
|
261
235
|
|
262
236
|
context "with deleted file" do
|
263
237
|
let(:file) {{:file => "spec/collector_spec.rb"}}
|
264
|
-
it {
|
265
|
-
|
238
|
+
it { should be_a Grit::Blob }
|
239
|
+
its(:name) { should == File.basename(file[:file]) }
|
240
|
+
end
|
241
|
+
|
242
|
+
context "with invalid blob" do
|
243
|
+
let(:file) {{:file => "dir/nothing.rb"}}
|
244
|
+
it { should be_nil }
|
266
245
|
end
|
267
246
|
end
|
268
247
|
|
data/spec/commits_spec.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
2
3
|
include GitStatistics
|
3
4
|
|
4
5
|
describe Commits do
|
5
|
-
let(:verbose) {false}
|
6
6
|
let(:limit) {100}
|
7
7
|
let(:fresh) {true}
|
8
8
|
let(:pretty) {false}
|
9
|
-
let(:collector) {Collector.new(
|
9
|
+
let(:collector) {Collector.new(limit, fresh, pretty)}
|
10
10
|
|
11
11
|
let(:commits) {collector.commits}
|
12
12
|
|
13
13
|
let(:fixture_file) {"multiple_authors.json"}
|
14
|
-
let(:save_file) {collector.commits_path
|
14
|
+
let(:save_file) { File.join(collector.commits_path, "0.json") }
|
15
15
|
let(:email) {false}
|
16
16
|
let(:merge) {false}
|
17
17
|
let(:sort) {:commits}
|
@@ -21,56 +21,66 @@ describe Commits do
|
|
21
21
|
commits.author_top_n_type(sort)
|
22
22
|
end
|
23
23
|
|
24
|
+
describe "#files_in_path" do
|
25
|
+
let(:path) { '/tmp/example' }
|
26
|
+
subject { commits.files_in_path }
|
27
|
+
before do
|
28
|
+
FileUtils.mkdir_p(path)
|
29
|
+
Dir.chdir(path) do
|
30
|
+
FileUtils.touch '0.json'
|
31
|
+
FileUtils.touch '1.json'
|
32
|
+
end
|
33
|
+
commits.stub(:path) { path }
|
34
|
+
end
|
35
|
+
after do
|
36
|
+
FileUtils.rm_rf(path)
|
37
|
+
end
|
38
|
+
its(:count) { should == 2 }
|
39
|
+
it { should_not include '.' }
|
40
|
+
it { should_not include '..' }
|
41
|
+
end
|
42
|
+
|
24
43
|
describe "#flush_commits" do
|
25
|
-
let(:commits) {collector.commits.load(fixture(fixture_file))}
|
44
|
+
let(:commits) {collector.commits.load(fixture(fixture_file).file)}
|
45
|
+
|
46
|
+
def commit_size_changes_from(beginning, opts = {})
|
47
|
+
commits.size.should == beginning
|
48
|
+
commits.flush_commits(opts[:force] || false)
|
49
|
+
commits.size.should == opts[:to]
|
50
|
+
end
|
26
51
|
|
27
52
|
context "with commits exceeding limit" do
|
28
53
|
let(:limit) {2}
|
29
|
-
it
|
30
|
-
commits.size.should == 3
|
31
|
-
commits.flush_commits
|
32
|
-
commits.size.should == 0
|
33
|
-
end
|
54
|
+
it { commit_size_changes_from(3, to: 0) }
|
34
55
|
end
|
35
56
|
|
36
57
|
context "with commits equal to limit" do
|
37
58
|
let(:limit) {3}
|
38
|
-
it
|
39
|
-
commits.size.should == 3
|
40
|
-
commits.flush_commits
|
41
|
-
commits.size.should == 0
|
42
|
-
end
|
59
|
+
it { commit_size_changes_from(3, to: 0) }
|
43
60
|
end
|
44
61
|
|
45
62
|
context "with commits less than limit" do
|
46
63
|
let(:limit) {5}
|
47
|
-
it
|
48
|
-
commits.size.should == 3
|
49
|
-
commits.flush_commits
|
50
|
-
commits.size.should == 3
|
51
|
-
end
|
64
|
+
it { commit_size_changes_from(3, to: 3) }
|
52
65
|
end
|
53
66
|
|
54
67
|
context "with commits less than limit but forced" do
|
55
68
|
let(:limit) {5}
|
56
|
-
it
|
57
|
-
commits.size.should == 3
|
58
|
-
commits.flush_commits(true)
|
59
|
-
commits.size.should == 0
|
60
|
-
end
|
69
|
+
it { commit_size_changes_from(3, to: 0, force: true) }
|
61
70
|
end
|
62
71
|
end
|
63
72
|
|
64
73
|
describe "#process_commits" do
|
65
|
-
let(:commits) {collector.commits.load(fixture(fixture_file))}
|
74
|
+
let(:commits) {collector.commits.load(fixture(fixture_file).file)}
|
66
75
|
let(:type) {:author}
|
76
|
+
subject { commits.stats[author_name] }
|
77
|
+
|
78
|
+
before do
|
79
|
+
commits.process_commits(type, merge)
|
80
|
+
end
|
67
81
|
|
68
82
|
context "with merge" do
|
69
83
|
let(:merge) {true}
|
70
|
-
subject {
|
71
|
-
commits.process_commits(type, merge)
|
72
|
-
commits.stats[author_name]
|
73
|
-
}
|
74
84
|
|
75
85
|
context "on first author" do
|
76
86
|
let(:author_name) {"Kevin Jalbert"}
|
@@ -102,10 +112,6 @@ describe Commits do
|
|
102
112
|
|
103
113
|
context "without merge" do
|
104
114
|
let(:merge) {false}
|
105
|
-
subject {
|
106
|
-
commits.process_commits(type, merge)
|
107
|
-
commits.stats[author_name]
|
108
|
-
}
|
109
115
|
|
110
116
|
context "on first author" do
|
111
117
|
let(:author_name) {"Kevin Jalbert"}
|
@@ -136,11 +142,11 @@ describe Commits do
|
|
136
142
|
|
137
143
|
describe "#author_top_n_type" do
|
138
144
|
let(:sort) {:deletions}
|
145
|
+
subject {stats[author]}
|
139
146
|
|
140
147
|
context "with valid data" do
|
141
148
|
context "on first author" do
|
142
|
-
author
|
143
|
-
subject {stats[author]}
|
149
|
+
let(:author) { 'John Smith' }
|
144
150
|
it {stats.has_key?(author).should be_true}
|
145
151
|
it {subject[:commits].should == 1}
|
146
152
|
it {subject[:deletions].should == 16}
|
@@ -151,8 +157,7 @@ describe Commits do
|
|
151
157
|
end
|
152
158
|
|
153
159
|
context "on second author" do
|
154
|
-
author
|
155
|
-
subject {stats[author]}
|
160
|
+
let(:author) { "Kevin Jalbert" }
|
156
161
|
it {stats.has_key?(author).should be_true}
|
157
162
|
it {subject[:commits].should == 1}
|
158
163
|
it {subject[:additions].should == 73}
|
@@ -170,22 +175,22 @@ describe Commits do
|
|
170
175
|
|
171
176
|
context "with invalid type" do
|
172
177
|
let(:sort) {:wrong}
|
173
|
-
it {stats.should
|
178
|
+
it { stats.should be_nil }
|
174
179
|
end
|
175
180
|
|
176
181
|
context "with invalid data" do
|
177
182
|
let(:fixture_file) {nil}
|
178
|
-
it {stats.should
|
183
|
+
it { stats.should be_nil }
|
179
184
|
end
|
180
185
|
end
|
181
186
|
|
182
187
|
describe "#calculate_statistics" do
|
183
188
|
let(:fixture_file) {"single_author_pretty.json"}
|
189
|
+
subject {stats[author]}
|
184
190
|
|
185
191
|
context "with email" do
|
186
192
|
let(:email) {true}
|
187
|
-
author
|
188
|
-
subject {stats[author]}
|
193
|
+
let(:author) { "kevin.j.jalbert@gmail.com" }
|
189
194
|
|
190
195
|
it {stats.has_key?(author).should be_true}
|
191
196
|
it {subject[:commits].should == 1}
|
@@ -202,8 +207,7 @@ describe Commits do
|
|
202
207
|
|
203
208
|
context "with merge" do
|
204
209
|
let(:merge) {true}
|
205
|
-
author
|
206
|
-
subject {stats[author]}
|
210
|
+
let(:author) { 'Kevin Jalbert' }
|
207
211
|
|
208
212
|
it {stats.has_key?(author).should be_true}
|
209
213
|
it {subject[:commits].should == 2}
|
@@ -334,10 +338,10 @@ describe Commits do
|
|
334
338
|
let(:pretty) {true}
|
335
339
|
|
336
340
|
it do
|
337
|
-
commits.load(fixture(fixture_file))
|
341
|
+
commits.load(fixture(fixture_file).file)
|
338
342
|
commits.save("tmp.json", pretty)
|
339
343
|
|
340
|
-
same = FileUtils.compare_file("tmp.json", fixture(fixture_file))
|
344
|
+
same = FileUtils.compare_file("tmp.json", fixture(fixture_file).file)
|
341
345
|
FileUtils.remove_file("tmp.json")
|
342
346
|
|
343
347
|
same.should be_true
|
@@ -349,10 +353,10 @@ describe Commits do
|
|
349
353
|
let(:pretty) {false}
|
350
354
|
|
351
355
|
it do
|
352
|
-
commits.load(fixture(fixture_file))
|
356
|
+
commits.load(fixture(fixture_file).file)
|
353
357
|
commits.save("tmp.json", pretty)
|
354
358
|
|
355
|
-
same = FileUtils.compare_file("tmp.json", fixture(fixture_file))
|
359
|
+
same = FileUtils.compare_file("tmp.json", fixture(fixture_file).file)
|
356
360
|
FileUtils.remove_file("tmp.json")
|
357
361
|
|
358
362
|
same.should be_true
|