mutant 0.8.7 → 0.8.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +5 -0
- data/README.md +64 -3
- data/config/flay.yml +1 -1
- data/lib/mutant.rb +2 -0
- data/lib/mutant/cli.rb +1 -1
- data/lib/mutant/env/bootstrap.rb +36 -8
- data/lib/mutant/expression/method.rb +3 -5
- data/lib/mutant/expression/methods.rb +2 -4
- data/lib/mutant/expression/namespace.rb +4 -8
- data/lib/mutant/matcher.rb +3 -18
- data/lib/mutant/matcher/chain.rb +7 -13
- data/lib/mutant/matcher/compiler.rb +2 -13
- data/lib/mutant/matcher/filter.rb +6 -19
- data/lib/mutant/matcher/method.rb +124 -104
- data/lib/mutant/matcher/method/instance.rb +40 -34
- data/lib/mutant/matcher/method/singleton.rb +80 -61
- data/lib/mutant/matcher/methods.rb +19 -29
- data/lib/mutant/matcher/namespace.rb +22 -16
- data/lib/mutant/matcher/null.rb +4 -7
- data/lib/mutant/matcher/scope.rb +23 -13
- data/lib/mutant/matcher/static.rb +17 -0
- data/lib/mutant/mutation.rb +0 -5
- data/lib/mutant/reporter/cli/format.rb +2 -3
- data/lib/mutant/reporter/cli/printer/env_progress.rb +37 -11
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +1 -1
- data/lib/mutant/scope.rb +6 -0
- data/lib/mutant/subject/method.rb +0 -7
- data/lib/mutant/subject/method/instance.rb +0 -10
- data/lib/mutant/subject/method/singleton.rb +0 -10
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +2 -1
- data/mutant-rspec.gemspec +1 -1
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/shared/method_matcher_behavior.rb +21 -14
- data/spec/spec_helper.rb +6 -0
- data/spec/unit/mutant/env/boostrap_spec.rb +88 -26
- data/spec/unit/mutant/env_spec.rb +0 -1
- data/spec/unit/mutant/expression/method_spec.rb +3 -3
- data/spec/unit/mutant/expression/methods_spec.rb +3 -4
- data/spec/unit/mutant/expression/namespace/flat_spec.rb +2 -3
- data/spec/unit/mutant/expression/namespace/recursive_spec.rb +2 -4
- data/spec/unit/mutant/matcher/chain_spec.rb +21 -29
- data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +16 -13
- data/spec/unit/mutant/matcher/compiler_spec.rb +49 -60
- data/spec/unit/mutant/matcher/filter_spec.rb +15 -31
- data/spec/unit/mutant/matcher/method/instance_spec.rb +84 -128
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +48 -52
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +21 -24
- data/spec/unit/mutant/matcher/methods/singleton_spec.rb +18 -21
- data/spec/unit/mutant/matcher/namespace_spec.rb +30 -38
- data/spec/unit/mutant/matcher/null_spec.rb +5 -20
- data/spec/unit/mutant/matcher/scope_spec.rb +33 -0
- data/spec/unit/mutant/matcher/static_spec.rb +11 -0
- data/spec/unit/mutant/mutation_spec.rb +30 -10
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +6 -0
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +2 -0
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +10 -0
- data/spec/unit/mutant/reporter/cli_spec.rb +4 -0
- data/spec/unit/mutant/subject/method/instance_spec.rb +0 -28
- data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -28
- data/test_app/Gemfile.rspec3.4 +7 -0
- data/test_app/lib/test_app.rb +16 -12
- data/test_app/lib/test_app/literal.rb +3 -0
- metadata +9 -2
@@ -1,76 +1,72 @@
|
|
1
|
-
RSpec.describe Mutant::Matcher::Method::Singleton, '#
|
2
|
-
subject { object.
|
3
|
-
|
4
|
-
let(:object) { described_class.new(
|
5
|
-
let(:
|
6
|
-
let(:
|
7
|
-
let(:
|
8
|
-
let(:
|
9
|
-
let(:
|
10
|
-
let(:
|
11
|
-
let(:
|
1
|
+
RSpec.describe Mutant::Matcher::Method::Singleton, '#call' do
|
2
|
+
subject { object.call(env) }
|
3
|
+
|
4
|
+
let(:object) { described_class.new(scope, method) }
|
5
|
+
let(:env) { test_env }
|
6
|
+
let(:method) { scope.method(method_name) }
|
7
|
+
let(:type) { :defs }
|
8
|
+
let(:method_name) { :foo }
|
9
|
+
let(:method_arity) { 0 }
|
10
|
+
let(:base) { TestApp::SingletonMethodTests }
|
11
|
+
let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
|
12
12
|
|
13
13
|
def name
|
14
|
-
node.children
|
14
|
+
node.children.fetch(1)
|
15
15
|
end
|
16
16
|
|
17
17
|
def arguments
|
18
|
-
node.children
|
18
|
+
node.children.fetch(2)
|
19
19
|
end
|
20
20
|
|
21
|
-
context 'on
|
21
|
+
context 'when also defined on lvar' do
|
22
|
+
let(:scope) { base::DefinedOnLvar }
|
23
|
+
let(:method_line) { 66 }
|
24
|
+
let(:expected_warnings) do
|
25
|
+
[
|
26
|
+
'Can only match :defs on :self or :const got :lvar unable to match'
|
27
|
+
]
|
28
|
+
end
|
22
29
|
|
23
|
-
|
24
|
-
|
25
|
-
let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
|
26
|
-
let(:method_line) { 66 }
|
30
|
+
include_examples 'skipped candidate'
|
31
|
+
end
|
27
32
|
|
28
|
-
|
33
|
+
context 'when defined on self' do
|
34
|
+
let(:scope) { base::DefinedOnSelf }
|
35
|
+
let(:method_line) { 61 }
|
29
36
|
|
30
|
-
|
31
|
-
|
32
|
-
expect(env.config.reporter.warn_calls).to(
|
33
|
-
include('Can only match :defs on :self or :const got :lvar unable to match')
|
34
|
-
)
|
35
|
-
end
|
36
|
-
end
|
37
|
+
it_should_behave_like 'a method matcher'
|
38
|
+
end
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
let(:
|
41
|
-
let(:method_line) {
|
40
|
+
context 'when defined on constant' do
|
41
|
+
context 'inside namespace' do
|
42
|
+
let(:scope) { base::DefinedOnConstant::InsideNamespace }
|
43
|
+
let(:method_line) { 71 }
|
42
44
|
|
43
45
|
it_should_behave_like 'a method matcher'
|
44
46
|
end
|
45
47
|
|
46
|
-
context '
|
48
|
+
context 'outside namespace' do
|
49
|
+
let(:scope) { base::DefinedOnConstant::OutsideNamespace }
|
50
|
+
let(:method_line) { 78 }
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
let(:method_line) { 71 }
|
52
|
-
|
53
|
-
it_should_behave_like 'a method matcher'
|
54
|
-
end
|
52
|
+
it_should_behave_like 'a method matcher'
|
53
|
+
end
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
context 'when defined multiple times in the same line' do
|
57
|
+
context 'with method on different scope' do
|
58
|
+
let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentScope }
|
59
|
+
let(:method_line) { 97 }
|
60
|
+
let(:method_arity) { 1 }
|
60
61
|
|
61
|
-
|
62
|
-
end
|
62
|
+
it_should_behave_like 'a method matcher'
|
63
63
|
end
|
64
64
|
|
65
|
-
context '
|
66
|
-
|
67
|
-
|
68
|
-
let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
|
69
|
-
let(:method_line) { 97 }
|
70
|
-
let(:method_arity) { 1 }
|
65
|
+
context 'with different name' do
|
66
|
+
let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentName }
|
67
|
+
let(:method_line) { 101 }
|
71
68
|
|
72
|
-
|
73
|
-
end
|
69
|
+
it_should_behave_like 'a method matcher'
|
74
70
|
end
|
75
71
|
end
|
76
72
|
end
|
@@ -1,10 +1,6 @@
|
|
1
|
-
RSpec.describe Mutant::Matcher::Methods::Instance, '#
|
2
|
-
let(:object) { described_class.new(
|
3
|
-
let(:env) { Fixtures::TEST_ENV
|
4
|
-
|
5
|
-
subject { object.each { |matcher| yields << matcher } }
|
6
|
-
|
7
|
-
let(:yields) { [] }
|
1
|
+
RSpec.describe Mutant::Matcher::Methods::Instance, '#call' do
|
2
|
+
let(:object) { described_class.new(class_under_test) }
|
3
|
+
let(:env) { Fixtures::TEST_ENV }
|
8
4
|
|
9
5
|
let(:class_under_test) do
|
10
6
|
parent = Module.new do
|
@@ -37,26 +33,27 @@ RSpec.describe Mutant::Matcher::Methods::Instance, '#each' do
|
|
37
33
|
end
|
38
34
|
end
|
39
35
|
|
40
|
-
let(:subject_a) {
|
41
|
-
let(:subject_b) {
|
42
|
-
let(:subject_c) {
|
43
|
-
|
44
|
-
let(:subjects) { [subject_a, subject_b, subject_c] }
|
36
|
+
let(:subject_a) { instance_double(Mutant::Subject) }
|
37
|
+
let(:subject_b) { instance_double(Mutant::Subject) }
|
38
|
+
let(:subject_c) { instance_double(Mutant::Subject) }
|
39
|
+
let(:subjects) { [subject_a, subject_b, subject_c] }
|
45
40
|
|
46
41
|
before do
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
.
|
42
|
+
{
|
43
|
+
method_a: subject_a,
|
44
|
+
method_b: subject_b,
|
45
|
+
method_c: subject_c
|
46
|
+
}.each do |method, subject|
|
47
|
+
matcher = instance_double(Mutant::Matcher)
|
48
|
+
expect(matcher).to receive(:call).with(env).and_return([subject])
|
49
|
+
|
50
|
+
expect(Mutant::Matcher::Method::Instance).to receive(:new)
|
51
|
+
.with(class_under_test, class_under_test.instance_method(method))
|
52
|
+
.and_return(matcher)
|
53
|
+
end
|
54
54
|
end
|
55
55
|
|
56
|
-
it '
|
57
|
-
|
58
|
-
expect(yields).to eql(subjects)
|
56
|
+
it 'returns expected subjects' do
|
57
|
+
expect(object.call(env)).to eql(subjects)
|
59
58
|
end
|
60
|
-
|
61
|
-
it_should_behave_like 'an #each method'
|
62
59
|
end
|
@@ -1,10 +1,6 @@
|
|
1
|
-
RSpec.describe Mutant::Matcher::Methods::Singleton, '#
|
2
|
-
let(:object) { described_class.new(
|
3
|
-
let(:env) { Fixtures::TEST_ENV
|
4
|
-
|
5
|
-
subject { object.each { |matcher| yields << matcher } }
|
6
|
-
|
7
|
-
let(:yields) { [] }
|
1
|
+
RSpec.describe Mutant::Matcher::Methods::Singleton, '#call' do
|
2
|
+
let(:object) { described_class.new(class_under_test) }
|
3
|
+
let(:env) { Fixtures::TEST_ENV }
|
8
4
|
|
9
5
|
let(:class_under_test) do
|
10
6
|
parent = Module.new do
|
@@ -32,26 +28,27 @@ RSpec.describe Mutant::Matcher::Methods::Singleton, '#each' do
|
|
32
28
|
end
|
33
29
|
end
|
34
30
|
|
35
|
-
let(:subject_a) {
|
36
|
-
let(:subject_b) {
|
37
|
-
let(:subject_c) {
|
31
|
+
let(:subject_a) { instance_double(Mutant::Subject, 'A') }
|
32
|
+
let(:subject_b) { instance_double(Mutant::Subject, 'B') }
|
33
|
+
let(:subject_c) { instance_double(Mutant::Subject, 'C') }
|
38
34
|
|
39
35
|
let(:subjects) { [subject_a, subject_b, subject_c] }
|
40
36
|
|
41
37
|
before do
|
42
38
|
matcher = Mutant::Matcher::Method::Singleton
|
43
|
-
allow(matcher).to receive(:new)
|
44
|
-
.with(env, class_under_test, class_under_test.method(:method_a)).and_return([subject_a])
|
45
|
-
allow(matcher).to receive(:new)
|
46
|
-
.with(env, class_under_test, class_under_test.method(:method_b)).and_return([subject_b])
|
47
|
-
allow(matcher).to receive(:new)
|
48
|
-
.with(env, class_under_test, class_under_test.method(:method_c)).and_return([subject_c])
|
49
|
-
end
|
50
39
|
|
51
|
-
|
52
|
-
|
53
|
-
|
40
|
+
{
|
41
|
+
method_a: subject_a,
|
42
|
+
method_b: subject_b,
|
43
|
+
method_c: subject_c
|
44
|
+
}.each do |method, subject|
|
45
|
+
allow(matcher).to receive(:new)
|
46
|
+
.with(class_under_test, class_under_test.method(method))
|
47
|
+
.and_return(Mutant::Matcher::Static.new([subject]))
|
48
|
+
end
|
54
49
|
end
|
55
50
|
|
56
|
-
|
51
|
+
it 'returns expected subjects' do
|
52
|
+
expect(object.call(env)).to eql(subjects)
|
53
|
+
end
|
57
54
|
end
|
@@ -1,44 +1,36 @@
|
|
1
|
-
RSpec.describe Mutant::Matcher::Namespace do
|
2
|
-
let(:object) { described_class.new(
|
3
|
-
let(:
|
4
|
-
let(:
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
[singleton_a, singleton_b, singleton_c].map do |scope|
|
25
|
-
Mutant::Matcher::Scope.new(env, scope, parse_expression(scope.name))
|
26
|
-
end
|
27
|
-
)
|
1
|
+
RSpec.describe Mutant::Matcher::Namespace, '#call' do
|
2
|
+
let(:object) { described_class.new(parse_expression('TestApp*')) }
|
3
|
+
let(:env) { instance_double(Mutant::Env) }
|
4
|
+
let(:raw_scope_a) { double('SingletonA', name: 'TestApp::Literal') }
|
5
|
+
|
6
|
+
let(:raw_scope_b) { double('SingletonB', name: 'TestApp::Foo') }
|
7
|
+
let(:raw_scope_c) { double('SingletonC', name: 'TestAppOther') }
|
8
|
+
let(:subject_a) { double('SubjectA') }
|
9
|
+
let(:subject_b) { double('SubjectB') }
|
10
|
+
|
11
|
+
before do
|
12
|
+
[
|
13
|
+
[Mutant::Matcher::Methods::Singleton, raw_scope_b, [subject_b]],
|
14
|
+
[Mutant::Matcher::Methods::Instance, raw_scope_b, []],
|
15
|
+
[Mutant::Matcher::Methods::Singleton, raw_scope_a, [subject_a]],
|
16
|
+
[Mutant::Matcher::Methods::Instance, raw_scope_a, []]
|
17
|
+
].each do |klass, scope, subjects|
|
18
|
+
matcher = instance_double(Mutant::Matcher)
|
19
|
+
expect(matcher).to receive(:call).with(env).and_return(subjects)
|
20
|
+
|
21
|
+
expect(klass).to receive(:new)
|
22
|
+
.with(scope)
|
23
|
+
.and_return(matcher)
|
28
24
|
end
|
29
25
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
it { should be_instance_of(to_enum.class) }
|
34
|
-
|
35
|
-
it 'yields the expected values' do
|
36
|
-
expect(subject.to_a).to eql(object.to_a)
|
26
|
+
allow(env).to receive(:matchable_scopes).and_return(
|
27
|
+
[raw_scope_a, raw_scope_b, raw_scope_c].map do |raw_scope|
|
28
|
+
Mutant::Scope.new(raw_scope, parse_expression(raw_scope.name))
|
37
29
|
end
|
38
|
-
|
30
|
+
)
|
31
|
+
end
|
39
32
|
|
40
|
-
|
41
|
-
|
42
|
-
end
|
33
|
+
it 'returns subjects' do
|
34
|
+
expect(object.call(env)).to eql([subject_a, subject_b])
|
43
35
|
end
|
44
36
|
end
|
@@ -1,24 +1,9 @@
|
|
1
|
-
RSpec.describe Mutant::Matcher::Null do
|
1
|
+
RSpec.describe Mutant::Matcher::Null, '#call' do
|
2
2
|
let(:object) { described_class.new }
|
3
|
+
let(:env) { instance_double(Mutant::Env) }
|
4
|
+
subject { object.call(env) }
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
subject { object.each { |entry| yields << entry } }
|
8
|
-
|
9
|
-
# it_should_behave_like 'an #each method'
|
10
|
-
context 'with no block' do
|
11
|
-
subject { object.each }
|
12
|
-
|
13
|
-
it { should be_instance_of(to_enum.class) }
|
14
|
-
|
15
|
-
it 'yields the expected values' do
|
16
|
-
expect(subject.to_a).to eql(object.to_a)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'should yield subjects' do
|
21
|
-
expect { subject }.not_to change { yields }.from([])
|
22
|
-
end
|
6
|
+
it 'returns no subjects' do
|
7
|
+
should eql([])
|
23
8
|
end
|
24
9
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
RSpec.describe Mutant::Matcher::Scope, '#call' do
|
2
|
+
let(:scope) { TestApp }
|
3
|
+
let(:object) { described_class.new(scope) }
|
4
|
+
let(:env) { instance_double(Mutant::Env) }
|
5
|
+
let(:matcher_a) { instance_double(Mutant::Matcher) }
|
6
|
+
let(:matcher_b) { instance_double(Mutant::Matcher) }
|
7
|
+
let(:subject_a) { instance_double(Mutant::Subject) }
|
8
|
+
let(:subject_b) { instance_double(Mutant::Subject) }
|
9
|
+
|
10
|
+
subject { object.call(env) }
|
11
|
+
|
12
|
+
before do
|
13
|
+
expect(Mutant::Matcher::Methods::Singleton).to receive(:new)
|
14
|
+
.with(scope)
|
15
|
+
.and_return(matcher_a)
|
16
|
+
|
17
|
+
expect(Mutant::Matcher::Methods::Instance).to receive(:new)
|
18
|
+
.with(scope)
|
19
|
+
.and_return(matcher_b)
|
20
|
+
|
21
|
+
expect(matcher_a).to receive(:call)
|
22
|
+
.with(env)
|
23
|
+
.and_return([subject_a])
|
24
|
+
|
25
|
+
expect(matcher_b).to receive(:call)
|
26
|
+
.with(env)
|
27
|
+
.and_return([subject_b])
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'concatenates subjects from matched singleton and instance methods' do
|
31
|
+
should eql([subject_a, subject_b])
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
RSpec.describe Mutant::Matcher::Static, '#call' do
|
2
|
+
let(:object) { described_class.new(subjects) }
|
3
|
+
let(:env) { instance_double(Mutant::Env) }
|
4
|
+
let(:subjects) { instance_double(Array) }
|
5
|
+
|
6
|
+
subject { object.call(env) }
|
7
|
+
|
8
|
+
it 'returns its predefined subjects' do
|
9
|
+
should be(subjects)
|
10
|
+
end
|
11
|
+
end
|
@@ -1,25 +1,45 @@
|
|
1
1
|
RSpec.describe Mutant::Mutation do
|
2
|
-
|
3
2
|
class TestMutation < Mutant::Mutation
|
4
3
|
SYMBOL = 'test'.freeze
|
5
4
|
end
|
6
5
|
|
7
6
|
let(:object) { TestMutation.new(mutation_subject, Mutant::AST::Nodes::N_NIL) }
|
8
|
-
let(:context) {
|
7
|
+
let(:context) { instance_double(Mutant::Context) }
|
9
8
|
|
10
9
|
let(:mutation_subject) do
|
11
|
-
|
12
|
-
|
10
|
+
instance_double(
|
11
|
+
Mutant::Subject,
|
13
12
|
identification: 'subject',
|
14
|
-
context:
|
15
|
-
source:
|
16
|
-
tests: tests
|
13
|
+
context: context,
|
14
|
+
source: 'original'
|
17
15
|
)
|
18
16
|
end
|
19
17
|
|
20
|
-
let(:test_a) {
|
21
|
-
let(:test_b) {
|
22
|
-
|
18
|
+
let(:test_a) { instance_double(Mutant::Test) }
|
19
|
+
let(:test_b) { instance_double(Mutant::Test) }
|
20
|
+
|
21
|
+
describe '#insert' do
|
22
|
+
subject { object.insert }
|
23
|
+
|
24
|
+
let(:root_node) { s(:foo) }
|
25
|
+
|
26
|
+
before do
|
27
|
+
expect(context).to receive(:root)
|
28
|
+
.with(object.node)
|
29
|
+
.and_return(root_node)
|
30
|
+
|
31
|
+
expect(mutation_subject).to receive(:prepare)
|
32
|
+
.ordered
|
33
|
+
.and_return(mutation_subject)
|
34
|
+
|
35
|
+
expect(Mutant::Loader::Eval).to receive(:call)
|
36
|
+
.ordered
|
37
|
+
.with(root_node, mutation_subject)
|
38
|
+
.and_return(Mutant::Loader::Eval)
|
39
|
+
end
|
40
|
+
|
41
|
+
it_should_behave_like 'a command method'
|
42
|
+
end
|
23
43
|
|
24
44
|
describe '#code' do
|
25
45
|
subject { object.code }
|