zaphod 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.bundle/config +1 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +86 -0
- data/Guardfile +20 -0
- data/LICENSE +198 -0
- data/README.org +59 -0
- data/Rakefile +9 -0
- data/lib/simplecov/formatter/zaphod_formatter.rb +40 -0
- data/lib/zaphod/change_set.rb +14 -0
- data/lib/zaphod/code_change.rb +23 -0
- data/lib/zaphod/configuration.rb +15 -0
- data/lib/zaphod/git.rb +38 -0
- data/lib/zaphod/source_control.rb +31 -0
- data/lib/zaphod/spike.rb +7 -0
- data/lib/zaphod/version.rb +3 -0
- data/lib/zaphod.rb +26 -0
- data/spec/do_spec.rb +8 -0
- data/spec/simplecov/formatter/zaphod_formatter_spec.rb +73 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/zaphod/change_set_spec.rb +59 -0
- data/spec/zaphod/code_change_spec.rb +76 -0
- data/spec/zaphod/configuration_spec.rb +20 -0
- data/spec/zaphod/git_spec.rb +84 -0
- data/spec/zaphod/source_control_spec.rb +49 -0
- data/spec/zaphod_spec.rb +50 -0
- data/zaphod.gemspec +35 -0
- metadata +241 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
require 'simplecov/formatter/zaphod_formatter'
|
4
|
+
|
5
|
+
describe SimpleCov::Formatter::ZaphodFormatter do
|
6
|
+
let( :result ) do
|
7
|
+
SimpleCov::Result.new(
|
8
|
+
File.expand_path( "./lib/zaphod/spike.rb" ) => [1, 1, 1, 0, nil, nil, nil]
|
9
|
+
)
|
10
|
+
end
|
11
|
+
|
12
|
+
let!( :source_control ) { Object.new }
|
13
|
+
|
14
|
+
before :each do
|
15
|
+
stub( Zaphod::SourceControl ).git { source_control }
|
16
|
+
stub( source_control ).changes { Zaphod::ChangeSet.new([]) }
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#format( result )" do
|
20
|
+
it "gets the current changes from source control" do
|
21
|
+
mock( Zaphod::SourceControl ).git( Dir.pwd ) { source_control }
|
22
|
+
subject.format result
|
23
|
+
end
|
24
|
+
|
25
|
+
context "when the uncovered lines include the current changes" do
|
26
|
+
let( :source_changes ) do
|
27
|
+
Zaphod::ChangeSet.new([
|
28
|
+
Zaphod::CodeChange.new( "./lib/zaphod/spike.rb", [" @var = \"foo\"\n"] )
|
29
|
+
])
|
30
|
+
end
|
31
|
+
|
32
|
+
before :each do
|
33
|
+
stub( source_control ).changes { source_changes }
|
34
|
+
end
|
35
|
+
|
36
|
+
it "runs the configured on_failure action, passing uncovered changes" do
|
37
|
+
failed = false
|
38
|
+
Zaphod.configure do |config|
|
39
|
+
config.on_failure { |diff| failed = diff }
|
40
|
+
end
|
41
|
+
|
42
|
+
subject.format result
|
43
|
+
|
44
|
+
expect( failed ).to eq( source_changes.changes )
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context "when the uncovered lines do not include the current changes" do
|
49
|
+
before :each do
|
50
|
+
stub( source_control ).changes { Hash.new }
|
51
|
+
end
|
52
|
+
|
53
|
+
it "proceeds normally" do
|
54
|
+
subject.format result
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#uncovered( result )" do
|
60
|
+
subject { described_class.new.uncovered result }
|
61
|
+
|
62
|
+
it { should_not be_empty }
|
63
|
+
|
64
|
+
it "includes a code set for the file in the result" do
|
65
|
+
subject.first.path.should eq File.expand_path("./lib/zaphod/spike.rb")
|
66
|
+
end
|
67
|
+
|
68
|
+
it "provides the uncovered source lines to the code set" do
|
69
|
+
code_change = subject.first
|
70
|
+
code_change.source.first.should =~ /@var/
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
2
|
+
|
3
|
+
require 'zaphod'
|
4
|
+
Zaphod.setup
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
8
|
+
config.run_all_when_everything_filtered = true
|
9
|
+
config.filter_run :focus
|
10
|
+
|
11
|
+
config.mock_with :rr
|
12
|
+
|
13
|
+
# Run specs in random order to surface order dependencies. If you find an
|
14
|
+
# order dependency and want to debug it, you can fix the order by providing
|
15
|
+
# the seed, which is printed after each run.
|
16
|
+
# --seed 1234
|
17
|
+
config.order = 'random'
|
18
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'zaphod/code_change'
|
4
|
+
require 'zaphod/change_set'
|
5
|
+
|
6
|
+
module Zaphod
|
7
|
+
describe ChangeSet do
|
8
|
+
let( :changes ) do
|
9
|
+
[
|
10
|
+
Zaphod::CodeChange.new( "/dev/null", ["stuff"] ),
|
11
|
+
Zaphod::CodeChange.new( "/dev/null", ["stuff"] ),
|
12
|
+
]
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "construction" do
|
16
|
+
it "accepts a list of CodeChanges" do
|
17
|
+
described_class.new changes
|
18
|
+
end
|
19
|
+
|
20
|
+
it "rejects duplicates" do
|
21
|
+
expect( described_class.new( changes ) ).to have( 1 ).item
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "iteration" do
|
26
|
+
subject do
|
27
|
+
described_class.new changes
|
28
|
+
end
|
29
|
+
|
30
|
+
it "yields each change to a given block" do
|
31
|
+
subject.map { |c| c.class }.uniq.should == [Zaphod::CodeChange]
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns an iterator if no block is given" do
|
35
|
+
i = subject.map
|
36
|
+
i.should be_an_instance_of Enumerator
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#intersection" do
|
41
|
+
let( :set1 ) do
|
42
|
+
described_class.new([
|
43
|
+
CodeChange.new( "/dev/null", ["baz"] ),
|
44
|
+
CodeChange.new( "./lib/zaphod/spike.rb", ["+ foo"] )
|
45
|
+
])
|
46
|
+
end
|
47
|
+
let( :set2 ) do
|
48
|
+
described_class.new([
|
49
|
+
CodeChange.new( "/dev/null", ["baz"] )
|
50
|
+
])
|
51
|
+
end
|
52
|
+
|
53
|
+
it do
|
54
|
+
expect( set1.intersection( set2 ) ).
|
55
|
+
to eq( Set.new([ CodeChange.new( "/dev/null", ["baz"] ) ]) )
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'zaphod/code_change'
|
3
|
+
module Zaphod
|
4
|
+
describe CodeChange do
|
5
|
+
describe "construction" do
|
6
|
+
it "accepts a list of source lines" do
|
7
|
+
source = ["require 'foo'", "puts 'bar'"]
|
8
|
+
set = Zaphod::CodeChange.new "./lib/zaphod/spike.rb", source
|
9
|
+
set.source.should == source
|
10
|
+
end
|
11
|
+
|
12
|
+
it "expands the given path" do
|
13
|
+
path = "./lib/zaphod/spike.rb"
|
14
|
+
expect( CodeChange.new( path ).path ).
|
15
|
+
to eq( File.expand_path( path ) )
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#eql?" do
|
20
|
+
context "when the paths and source are equal" do
|
21
|
+
let( :change1 ) { CodeChange.new ".lib/zaphod/spike.rb", ["foo"] }
|
22
|
+
let( :change2 ) { CodeChange.new ".lib/zaphod/spike.rb", ["foo"] }
|
23
|
+
|
24
|
+
it( "is true" ) { expect( change1 ).to eql( change2 ) }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "when the source list is empty" do
|
28
|
+
let( :change1 ) { CodeChange.new ".lib/zaphod/spike.rb" }
|
29
|
+
let( :change2 ) { CodeChange.new ".lib/zaphod/spike.rb" }
|
30
|
+
|
31
|
+
it( "is not true" ) { expect( change1 ).to_not eql( change2 ) }
|
32
|
+
end
|
33
|
+
|
34
|
+
context "when the sources differ" do
|
35
|
+
let( :change1 ) { CodeChange.new ".lib/zaphod/spike.rb", ["bar"] }
|
36
|
+
let( :change3 ) { CodeChange.new ".lib/zaphod/spike.rb", ["foo"] }
|
37
|
+
|
38
|
+
it( "is not true" ) { expect( change1 ).to_not eql( change3 ) }
|
39
|
+
end
|
40
|
+
|
41
|
+
context "when the sources overlap" do
|
42
|
+
let( :change1 ) do
|
43
|
+
CodeChange.new "./lib/zaphod/spike.rb", [
|
44
|
+
"require 'foo'",
|
45
|
+
"Foo.bar!"
|
46
|
+
]
|
47
|
+
end
|
48
|
+
|
49
|
+
let( :change2 ) do
|
50
|
+
CodeChange.new "./lib/zaphod/spike.rb", [
|
51
|
+
"require 'foo'",
|
52
|
+
"Foo.bar!",
|
53
|
+
"Bar.baz"
|
54
|
+
]
|
55
|
+
end
|
56
|
+
|
57
|
+
it( "is true" ) { expect( change1 ).to eql( change2 ) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
describe "#hash" do
|
62
|
+
let( :change1 ) { CodeChange.new ".lib/zaphod/spike.rb" }
|
63
|
+
let( :change2 ) { CodeChange.new ".lib/zaphod/spike.rb" }
|
64
|
+
let( :change3 ) { CodeChange.new ".lib/zaphod/spike.rb", ["+foo"] }
|
65
|
+
|
66
|
+
it "is the same for two changes that are eql" do
|
67
|
+
expect( change1.hash ).to eq( change2.hash )
|
68
|
+
end
|
69
|
+
|
70
|
+
it "differs for two changes that have inequal sources" do
|
71
|
+
expect( change2.hash ).to_not eq( change3.hash )
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "zaphod/configuration"
|
3
|
+
|
4
|
+
describe Zaphod::Configuration do
|
5
|
+
subject( :config ) { described_class.new }
|
6
|
+
|
7
|
+
describe "#on_failure" do
|
8
|
+
it "stores a proc, if given" do
|
9
|
+
proc = Proc.new { :foo }
|
10
|
+
config.on_failure( &proc )
|
11
|
+
expect( config.on_failure ).to eq( proc )
|
12
|
+
end
|
13
|
+
|
14
|
+
it "defaults to a SystemExit" do
|
15
|
+
expect do
|
16
|
+
config.on_failure.call
|
17
|
+
end.to raise_error( SystemExit )
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'zaphod/git'
|
3
|
+
|
4
|
+
describe Zaphod::Git do
|
5
|
+
let( :git ) { stub!.diff_index { DIFF }.subject }
|
6
|
+
let( :grit ) { stub!.git { git }.subject }
|
7
|
+
|
8
|
+
subject { described_class.new grit }
|
9
|
+
|
10
|
+
describe "to get current changes in the git repository" do
|
11
|
+
it "calls :diff_index on the Grit git object" do
|
12
|
+
mock( git ).diff_index({ p: true }, "HEAD") { DIFF }
|
13
|
+
|
14
|
+
subject.diff
|
15
|
+
end
|
16
|
+
|
17
|
+
it "returns the patch split into a Hash of file => patch sets" do
|
18
|
+
subject.diff.keys.should include(
|
19
|
+
"./spec/spec_helper.rb",
|
20
|
+
"./spec/zaphod/source_control_spec.rb"
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
DIFF = <<-EOS
|
26
|
+
diff --git /dev/null b/spec/spec_helper.rb
|
27
|
+
--- /dev/null
|
28
|
+
+++ b/spec/spec_helper.rb
|
29
|
+
@@ -1 +1,29 @@
|
30
|
+
+# This file was generated by the `rspec --init` command. Conventionally, all
|
31
|
+
+# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
32
|
+
+# Require this file using `require "spec_helper"` to ensure that it is only
|
33
|
+
+# loaded once.
|
34
|
+
+#
|
35
|
+
+# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
36
|
+
+
|
37
|
+
+require 'simplecov'
|
38
|
+
+require 'zaphod'
|
39
|
+
+
|
40
|
+
+SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
41
|
+
+ SimpleCov::Formatter::HTMLFormatter,
|
42
|
+
+ SimpleCov::Formatter::ZaphodFormatter
|
43
|
+
+]
|
44
|
+
+
|
45
|
+
+SimpleCov.start
|
46
|
+
+
|
47
|
+
+RSpec.configure do |config|
|
48
|
+
+ config.treat_symbols_as_metadata_keys_with_true_values = true
|
49
|
+
+ config.run_all_when_everything_filtered = true
|
50
|
+
+ config.filter_run :focus
|
51
|
+
+
|
52
|
+
+ # Run specs in random order to surface order dependencies. If you find an
|
53
|
+
+ # order dependency and want to debug it, you can fix the order by providing
|
54
|
+
+ # the seed, which is printed after each run.
|
55
|
+
+ # --seed 1234
|
56
|
+
+ config.order = 'random'
|
57
|
+
+end
|
58
|
+
diff --git a/spec/zaphod/source_control_spec.rbf b/spec/zaphod/source_control_spec.rb
|
59
|
+
index 73d4e77..8ef378d 100644
|
60
|
+
--- a/spec/zaphod/source_control_spec.rb
|
61
|
+
+++ b/spec/zaphod/source_control_spec.rb
|
62
|
+
@@ -6,6 +6,7 @@ describe Zaphod::Git do
|
63
|
+
File.expand_path( File.join __FILE__, "..", ".." )
|
64
|
+
)
|
65
|
+
|
66
|
+
+
|
67
|
+
describe "#initialize" do
|
68
|
+
it "accepts a repository" do
|
69
|
+
described_class.new Grit::Repo.new REPO_PATH
|
70
|
+
@@ -13,10 +14,9 @@ describe Zaphod::Git do
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#changes", integrated: true do
|
74
|
+
- let( :first_commit ) { stub diffs: [last_diff] }
|
75
|
+
- let( :commits ) { [first_commit] }
|
76
|
+
- let( :repository ) { stub commits: commits }
|
77
|
+
- let( :last_diff ) { stub diff: DIFF, b_path: "spec/spec_helper.rb" }
|
78
|
+
+ let( :patch ) { DIFF }
|
79
|
+
+ let( :git_native ) { stub diff_index: patch }
|
80
|
+
+ let( :repository ) { stub git: git_native }
|
81
|
+
|
82
|
+
let( :git ) { described_class.new repository }
|
83
|
+
EOS
|
84
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
describe Zaphod::SourceControl do
|
5
|
+
REPO_PATH = File.dirname(
|
6
|
+
File.expand_path( File.join __FILE__, "..", ".." )
|
7
|
+
)
|
8
|
+
|
9
|
+
describe "#initialize" do
|
10
|
+
it "accepts a repository" do
|
11
|
+
described_class.new Grit::Repo.new REPO_PATH
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#changes" do
|
16
|
+
let( :patch_map ) do
|
17
|
+
{
|
18
|
+
"./spec/spec_helper.rb" => "+ require 'rspec'\n",
|
19
|
+
"./spec/zaphod/source_control_spec.rb" => "+ require 'spec_helper'\n"
|
20
|
+
}
|
21
|
+
end
|
22
|
+
let( :repository ) { stub!.diff { patch_map }.subject }
|
23
|
+
|
24
|
+
subject { described_class.new repository }
|
25
|
+
|
26
|
+
it do
|
27
|
+
subject.changes.should be_an_instance_of( Zaphod::ChangeSet )
|
28
|
+
subject.changes.should_not be_empty
|
29
|
+
|
30
|
+
subject.changes.each do |change|
|
31
|
+
File.exist?( change.path ).should be_true, change.path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "generates a row for each file in the diff" do
|
36
|
+
subject.changes.length.should eq 2
|
37
|
+
end
|
38
|
+
|
39
|
+
it "passes the additions to each code set" do
|
40
|
+
subject.changes.first.source.length.should eq(
|
41
|
+
patch_map["./spec/spec_helper.rb"].lines.select { |l| l =~ /^[+][^+]/ }.to_a.size
|
42
|
+
)
|
43
|
+
end
|
44
|
+
|
45
|
+
it "strips the plusses off the lines" do
|
46
|
+
subject.changes.first.source.first.should_not start_with( "+" )
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/spec/zaphod_spec.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Zaphod do
|
4
|
+
describe ".configure" do
|
5
|
+
it "takes a block" do
|
6
|
+
Zaphod.configure { :foo }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "yields a configuration object" do
|
10
|
+
Zaphod.configure do |config|
|
11
|
+
expect( config ).to be_an_instance_of( Zaphod::Configuration )
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "yields the same object on repeated calls" do
|
16
|
+
config = nil
|
17
|
+
Zaphod.configure { |c| config = c }
|
18
|
+
Zaphod.configure do |c|
|
19
|
+
expect( c ).to be( config )
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".setup" do
|
25
|
+
it "sets the SimpleCov formatter to include the Zaphod formatter" do
|
26
|
+
Zaphod.setup
|
27
|
+
|
28
|
+
expected_formatters = [
|
29
|
+
SimpleCov::Formatter::HTMLFormatter,
|
30
|
+
SimpleCov::Formatter::ZaphodFormatter
|
31
|
+
]
|
32
|
+
|
33
|
+
expect( SimpleCov.formatter.new.formatters ).to eq( expected_formatters )
|
34
|
+
end
|
35
|
+
|
36
|
+
it "starts simplecov" do
|
37
|
+
mock( SimpleCov ).start
|
38
|
+
|
39
|
+
Zaphod.setup
|
40
|
+
end
|
41
|
+
|
42
|
+
it "accepts a configuration block" do
|
43
|
+
configuration = nil
|
44
|
+
Zaphod.setup do |config|
|
45
|
+
configuration = config
|
46
|
+
end
|
47
|
+
expect( configuration ).to be_an_instance_of( Zaphod::Configuration )
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/zaphod.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.push File.expand_path( "../lib", __FILE__ )
|
2
|
+
require "zaphod/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |spec|
|
5
|
+
spec.name = "zaphod"
|
6
|
+
spec.version = Zaphod::VERSION
|
7
|
+
|
8
|
+
spec.authors = ["Toby Tripp"]
|
9
|
+
spec.email = %q{toby.tripp+gems@gmail.com}
|
10
|
+
spec.homepage = %q{http://github.com/tobytripp/zaphod}
|
11
|
+
|
12
|
+
spec.summary = %q{Catch untested commits and report them.}
|
13
|
+
spec.description = %q{}
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split("\n")
|
16
|
+
spec.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
17
|
+
spec.require_paths = ["lib"]
|
18
|
+
|
19
|
+
spec.extra_rdoc_files = %w[README.org]
|
20
|
+
spec.rdoc_options = ["--charset=UTF-8"]
|
21
|
+
|
22
|
+
spec.add_dependency "grit", "~> 2.5"
|
23
|
+
spec.add_dependency "simplecov", "~> 0.8"
|
24
|
+
|
25
|
+
spec.add_development_dependency "rake", "~> 10.1"
|
26
|
+
spec.add_development_dependency "rr", "~> 1.1"
|
27
|
+
spec.add_development_dependency "rspec", "~> 2.14"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "guard", "~> 2.3"
|
30
|
+
spec.add_development_dependency "guard-rspec", "~> 4.2"
|
31
|
+
spec.add_development_dependency "guard-bundler"
|
32
|
+
spec.add_development_dependency "guard-shell"
|
33
|
+
spec.add_development_dependency "rb-fsevent"
|
34
|
+
spec.add_development_dependency 'rb-readline'
|
35
|
+
end
|