mutant 0.8.7 → 0.8.8

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.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +5 -0
  3. data/README.md +64 -3
  4. data/config/flay.yml +1 -1
  5. data/lib/mutant.rb +2 -0
  6. data/lib/mutant/cli.rb +1 -1
  7. data/lib/mutant/env/bootstrap.rb +36 -8
  8. data/lib/mutant/expression/method.rb +3 -5
  9. data/lib/mutant/expression/methods.rb +2 -4
  10. data/lib/mutant/expression/namespace.rb +4 -8
  11. data/lib/mutant/matcher.rb +3 -18
  12. data/lib/mutant/matcher/chain.rb +7 -13
  13. data/lib/mutant/matcher/compiler.rb +2 -13
  14. data/lib/mutant/matcher/filter.rb +6 -19
  15. data/lib/mutant/matcher/method.rb +124 -104
  16. data/lib/mutant/matcher/method/instance.rb +40 -34
  17. data/lib/mutant/matcher/method/singleton.rb +80 -61
  18. data/lib/mutant/matcher/methods.rb +19 -29
  19. data/lib/mutant/matcher/namespace.rb +22 -16
  20. data/lib/mutant/matcher/null.rb +4 -7
  21. data/lib/mutant/matcher/scope.rb +23 -13
  22. data/lib/mutant/matcher/static.rb +17 -0
  23. data/lib/mutant/mutation.rb +0 -5
  24. data/lib/mutant/reporter/cli/format.rb +2 -3
  25. data/lib/mutant/reporter/cli/printer/env_progress.rb +37 -11
  26. data/lib/mutant/reporter/cli/printer/status_progressive.rb +1 -1
  27. data/lib/mutant/scope.rb +6 -0
  28. data/lib/mutant/subject/method.rb +0 -7
  29. data/lib/mutant/subject/method/instance.rb +0 -10
  30. data/lib/mutant/subject/method/singleton.rb +0 -10
  31. data/lib/mutant/version.rb +1 -1
  32. data/lib/mutant/zombifier.rb +2 -1
  33. data/mutant-rspec.gemspec +1 -1
  34. data/spec/integration/mutant/rspec_spec.rb +1 -1
  35. data/spec/shared/method_matcher_behavior.rb +21 -14
  36. data/spec/spec_helper.rb +6 -0
  37. data/spec/unit/mutant/env/boostrap_spec.rb +88 -26
  38. data/spec/unit/mutant/env_spec.rb +0 -1
  39. data/spec/unit/mutant/expression/method_spec.rb +3 -3
  40. data/spec/unit/mutant/expression/methods_spec.rb +3 -4
  41. data/spec/unit/mutant/expression/namespace/flat_spec.rb +2 -3
  42. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +2 -4
  43. data/spec/unit/mutant/matcher/chain_spec.rb +21 -29
  44. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +16 -13
  45. data/spec/unit/mutant/matcher/compiler_spec.rb +49 -60
  46. data/spec/unit/mutant/matcher/filter_spec.rb +15 -31
  47. data/spec/unit/mutant/matcher/method/instance_spec.rb +84 -128
  48. data/spec/unit/mutant/matcher/method/singleton_spec.rb +48 -52
  49. data/spec/unit/mutant/matcher/methods/instance_spec.rb +21 -24
  50. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +18 -21
  51. data/spec/unit/mutant/matcher/namespace_spec.rb +30 -38
  52. data/spec/unit/mutant/matcher/null_spec.rb +5 -20
  53. data/spec/unit/mutant/matcher/scope_spec.rb +33 -0
  54. data/spec/unit/mutant/matcher/static_spec.rb +11 -0
  55. data/spec/unit/mutant/mutation_spec.rb +30 -10
  56. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +6 -0
  57. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +2 -0
  58. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +10 -0
  59. data/spec/unit/mutant/reporter/cli_spec.rb +4 -0
  60. data/spec/unit/mutant/subject/method/instance_spec.rb +0 -28
  61. data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -28
  62. data/test_app/Gemfile.rspec3.4 +7 -0
  63. data/test_app/lib/test_app.rb +16 -12
  64. data/test_app/lib/test_app/literal.rb +3 -0
  65. metadata +9 -2
@@ -55,7 +55,6 @@ RSpec.describe Mutant::Env do
55
55
 
56
56
  before do
57
57
  expect(isolation).to receive(:call).and_yield.and_return(test_result)
58
- expect(mutation_subject).to receive(:public?).and_return(true).ordered
59
58
  expect(mutation_subject).to receive(:prepare).and_return(mutation_subject).ordered
60
59
  expect(context).to receive(:root).with(s(:nil)).and_return(wrapped_node).ordered
61
60
  expect(Mutant::Loader::Eval).to receive(:call).with(wrapped_node, mutation_subject).and_return(nil).ordered
@@ -23,13 +23,13 @@ RSpec.describe Mutant::Expression::Method do
23
23
  end
24
24
 
25
25
  describe '#matcher' do
26
- subject { object.matcher(env) }
26
+ subject { object.matcher }
27
27
 
28
28
  context 'with an instance method' do
29
29
  let(:input) { instance_method }
30
30
 
31
31
  it 'returns correct matcher' do
32
- expect(subject.map(&:expression)).to eql([object])
32
+ expect(subject.call(env).map(&:expression)).to eql([object])
33
33
  end
34
34
  end
35
35
 
@@ -37,7 +37,7 @@ RSpec.describe Mutant::Expression::Method do
37
37
  let(:input) { singleton_method }
38
38
 
39
39
  it 'returns correct matcher' do
40
- expect(subject.map(&:expression)).to eql([object])
40
+ expect(subject.call(env).map(&:expression)).to eql([object])
41
41
  end
42
42
  end
43
43
  end
@@ -1,5 +1,4 @@
1
1
  RSpec.describe Mutant::Expression::Methods do
2
- let(:env) { Fixtures::TEST_ENV }
3
2
  let(:object) { described_class.new(attributes) }
4
3
 
5
4
  describe '#match_length' do
@@ -43,18 +42,18 @@ RSpec.describe Mutant::Expression::Methods do
43
42
  end
44
43
 
45
44
  describe '#matcher' do
46
- subject { object.matcher(env) }
45
+ subject { object.matcher }
47
46
 
48
47
  context 'with an instance method' do
49
48
  let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '#' } }
50
49
 
51
- it { should eql(Mutant::Matcher::Methods::Instance.new(env, TestApp::Literal)) }
50
+ it { should eql(Mutant::Matcher::Methods::Instance.new(TestApp::Literal)) }
52
51
  end
53
52
 
54
53
  context 'with a singleton method' do
55
54
  let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '.' } }
56
55
 
57
- it { should eql(Mutant::Matcher::Methods::Singleton.new(env, TestApp::Literal)) }
56
+ it { should eql(Mutant::Matcher::Methods::Singleton.new(TestApp::Literal)) }
58
57
  end
59
58
  end
60
59
  end
@@ -1,12 +1,11 @@
1
1
  RSpec.describe Mutant::Expression::Namespace::Exact do
2
2
  let(:object) { parse_expression(input) }
3
- let(:env) { Fixtures::TEST_ENV }
4
3
  let(:input) { 'TestApp::Literal' }
5
4
 
6
5
  describe '#matcher' do
7
- subject { object.matcher(env) }
6
+ subject { object.matcher }
8
7
 
9
- it { should eql(Mutant::Matcher::Scope.new(env, TestApp::Literal, object)) }
8
+ it { should eql(Mutant::Matcher::Scope.new(TestApp::Literal)) }
10
9
  end
11
10
 
12
11
  describe '#match_length' do
@@ -1,13 +1,11 @@
1
1
  RSpec.describe Mutant::Expression::Namespace::Recursive do
2
-
3
2
  let(:object) { parse_expression(input) }
4
3
  let(:input) { 'TestApp::Literal*' }
5
- let(:env) { Fixtures::TEST_ENV }
6
4
 
7
5
  describe '#matcher' do
8
- subject { object.matcher(env) }
6
+ subject { object.matcher }
9
7
 
10
- it { should eql(Mutant::Matcher::Namespace.new(env, object)) }
8
+ it { should eql(Mutant::Matcher::Namespace.new(object)) }
11
9
  end
12
10
 
13
11
  describe '#syntax' do
@@ -1,32 +1,24 @@
1
- RSpec.describe Mutant::Matcher::Chain do
2
-
3
- let(:object) { described_class.new(matchers) }
4
-
5
- describe '#each' do
6
- let(:yields) { [] }
7
- subject { object.each { |entry| yields << entry } }
8
-
9
- let(:matchers) { [matcher_a, matcher_b] }
10
-
11
- let(:matcher_a) { [subject_a] }
12
- let(:matcher_b) { [subject_b] }
13
-
14
- let(:subject_a) { double('Subject A') }
15
- let(:subject_b) { double('Subject B') }
16
-
17
- # it_should_behave_like 'an #each method'
18
- context 'with no block' do
19
- subject { object.each }
20
-
21
- it { should be_instance_of(to_enum.class) }
22
-
23
- it 'yields the expected values' do
24
- expect(subject.to_a).to eql(object.to_a)
25
- end
26
- end
1
+ RSpec.describe Mutant::Matcher::Chain, '#call' do
2
+ subject { object.call(env) }
3
+
4
+ let(:object) { described_class.new([matcher_a, matcher_b]) }
5
+ let(:env) { instance_double(Mutant::Env) }
6
+ let(:matcher_a) { instance_double(Mutant::Matcher) }
7
+ let(:matcher_b) { instance_double(Mutant::Matcher) }
8
+ let(:subject_a) { instance_double(Mutant::Subject) }
9
+ let(:subject_b) { instance_double(Mutant::Subject) }
10
+
11
+ before do
12
+ expect(matcher_a).to receive(:call)
13
+ .with(env)
14
+ .and_return([subject_a])
15
+
16
+ expect(matcher_b).to receive(:call)
17
+ .with(env)
18
+ .and_return([subject_b])
19
+ end
27
20
 
28
- it 'should yield subjects' do
29
- expect { subject }.to change { yields }.from([]).to([subject_a, subject_b])
30
- end
21
+ it 'returns concatenated matches' do
22
+ should eql([subject_a, subject_b])
31
23
  end
32
24
  end
@@ -1,21 +1,24 @@
1
- RSpec.describe Mutant::Matcher::Compiler::SubjectPrefix do
2
- let(:object) { described_class.new(parse_expression('Foo*')) }
1
+ RSpec.describe Mutant::Matcher::Compiler::SubjectPrefix, '#call' do
2
+ let(:object) { described_class.new(parse_expression('Foo*')) }
3
3
 
4
- let(:_subject) { double('Subject', expression: parse_expression(subject_expression)) }
4
+ let(:_subject) do
5
+ instance_double(
6
+ Mutant::Subject,
7
+ expression: parse_expression(subject_expression)
8
+ )
9
+ end
5
10
 
6
- describe '#call' do
7
- subject { object.call(_subject) }
11
+ subject { object.call(_subject) }
8
12
 
9
- context 'when subject expression is prefixed by expression' do
10
- let(:subject_expression) { 'Foo::Bar' }
13
+ context 'when subject expression is prefixed by expression' do
14
+ let(:subject_expression) { 'Foo::Bar' }
11
15
 
12
- it { should be(true) }
13
- end
16
+ it { should be(true) }
17
+ end
14
18
 
15
- context 'when subject expression is NOT prefixed by expression' do
16
- let(:subject_expression) { 'Bar' }
19
+ context 'when subject expression is NOT prefixed by expression' do
20
+ let(:subject_expression) { 'Bar' }
17
21
 
18
- it { should be(false) }
19
- end
22
+ it { should be(false) }
20
23
  end
21
24
  end
@@ -1,89 +1,78 @@
1
- RSpec.describe Mutant::Matcher::Compiler do
2
- let(:object) { described_class }
3
-
4
- let(:env) { Fixtures::TEST_ENV }
5
-
6
- let(:expression_a) { parse_expression('Foo*') }
7
- let(:expression_b) { parse_expression('Bar*') }
8
-
9
- let(:matcher_a) { expression_a.matcher(env) }
10
- let(:matcher_b) { expression_b.matcher(env) }
1
+ RSpec.describe Mutant::Matcher::Compiler, '#call' do
2
+ let(:object) { described_class }
3
+ let(:env) { Fixtures::TEST_ENV }
4
+ let(:matcher_config) { Mutant::Matcher::Config::DEFAULT }
5
+ let(:expression_a) { parse_expression('Foo*') }
6
+ let(:expression_b) { parse_expression('Bar*') }
7
+ let(:matcher_a) { expression_a.matcher }
8
+ let(:matcher_b) { expression_b.matcher }
11
9
 
12
10
  let(:expected_matcher) do
13
- Mutant::Matcher::Filter.new(expected_positive_matcher, expected_predicate)
11
+ Mutant::Matcher::Filter.new(
12
+ expected_positive_matcher,
13
+ expected_predicate
14
+ )
14
15
  end
15
16
 
16
17
  let(:expected_predicate) do
17
18
  Morpher.compile(s(:and, s(:negate, s(:or)), s(:and)))
18
19
  end
19
20
 
20
- describe '.call' do
21
- subject { object.call(env, matcher_config.with(attributes)) }
21
+ subject { object.call(matcher_config.with(attributes)) }
22
22
 
23
- let(:matcher_config) { Mutant::Matcher::Config::DEFAULT }
23
+ context 'on empty config' do
24
+ let(:attributes) { {} }
24
25
 
25
- context 'on empty config' do
26
- let(:attributes) { {} }
26
+ let(:expected_positive_matcher) { Mutant::Matcher::Chain.new([]) }
27
27
 
28
- let(:expected_positive_matcher) { Mutant::Matcher::Chain.new([]) }
28
+ it { should eql(expected_matcher) }
29
+ end
29
30
 
30
- it { should eql(expected_matcher) }
31
+ context 'on config with match expression' do
32
+ let(:expected_predicate) do
33
+ Morpher::Evaluator::Predicate::Boolean::And.new(
34
+ [
35
+ Morpher::Evaluator::Predicate::Negation.new(
36
+ Morpher::Evaluator::Predicate::Boolean::Or.new(ignore_expression_predicates)
37
+ ),
38
+ Morpher::Evaluator::Predicate::Boolean::And.new(subject_filter_predicates)
39
+ ]
40
+ )
31
41
  end
32
42
 
33
- context 'on config with match expression' do
34
- let(:expected_predicate) do
35
- Morpher::Evaluator::Predicate::Boolean::And.new(
36
- [
37
- Morpher::Evaluator::Predicate::Negation.new(
38
- Morpher::Evaluator::Predicate::Boolean::Or.new(ignore_expression_predicates)
39
- ),
40
- Morpher::Evaluator::Predicate::Boolean::And.new(subject_filter_predicates)
41
- ]
42
- )
43
- end
43
+ let(:expected_positive_matcher) { Mutant::Matcher::Chain.new([matcher_a]) }
44
+ let(:attributes) { { match_expressions: [expression_a] } }
45
+ let(:ignore_expression_predicates) { [] }
46
+ let(:subject_filter_predicates) { [] }
44
47
 
45
- let(:expected_positive_matcher) { Mutant::Matcher::Chain.new([matcher_a]) }
46
- let(:attributes) { { match_expressions: [expression_a] } }
47
- let(:ignore_expression_predicates) { [] }
48
- let(:subject_filter_predicates) { [] }
48
+ context 'and no other constraints' do
49
+ it { should eql(expected_matcher) }
50
+ end
49
51
 
50
- context 'and no other constraints' do
51
- it { should eql(expected_matcher) }
52
+ context 'and ignore expressions' do
53
+ let(:attributes) do
54
+ super().merge(ignore_expressions: [expression_b])
52
55
  end
53
56
 
54
- context 'and ignore expressions' do
55
- let(:attributes) do
56
- super().merge(ignore_expressions: [expression_b])
57
- end
58
-
59
- let(:ignore_expression_predicates) do
60
- [Mutant::Matcher::Compiler::SubjectPrefix.new(expression_b)]
61
- end
62
-
63
- it { should eql(expected_matcher) }
57
+ let(:ignore_expression_predicates) do
58
+ [Mutant::Matcher::Compiler::SubjectPrefix.new(expression_b)]
64
59
  end
65
60
 
66
- context 'and subject filters' do
67
- let(:filter) { double('filter') }
68
-
69
- let(:attributes) do
70
- super().merge(subject_filters: [filter])
71
- end
61
+ it { should eql(expected_matcher) }
62
+ end
72
63
 
73
- let(:subject_filter_predicates) do
74
- [filter]
75
- end
64
+ context 'and subject filters' do
65
+ let(:filter) { double('filter') }
76
66
 
77
- it { should eql(expected_matcher) }
67
+ let(:attributes) do
68
+ super().merge(subject_filters: [filter])
78
69
  end
79
- end
80
70
 
81
- context 'on config with multiple match expressions' do
82
- let(:attributes) do
83
- { match_expressions: [expression_a, expression_b] }
71
+ let(:subject_filter_predicates) do
72
+ [filter]
84
73
  end
85
74
 
86
- let(:expected_positive_matcher) { Mutant::Matcher::Chain.new([matcher_a, matcher_b]) }
75
+ it { should eql(expected_matcher) }
87
76
  end
88
77
  end
89
78
  end
@@ -1,36 +1,20 @@
1
- RSpec.describe Mutant::Matcher::Filter do
2
- let(:object) { described_class.new(matcher, predicate) }
3
- let(:matcher) { [subject_a, subject_b] }
4
- let(:subject_a) { double('Subject A') }
5
- let(:subject_b) { double('Subject B') }
6
-
7
- describe '#each' do
8
- let(:yields) { [] }
9
- subject { object.each { |entry| yields << entry } }
10
-
11
- let(:predicate) { ->(node) { node.eql?(subject_a) } }
12
-
13
- # it_should_behave_like 'an #each method'
14
- context 'with no block' do
15
- subject { object.each }
16
-
17
- it { should be_instance_of(to_enum.class) }
1
+ RSpec.describe Mutant::Matcher::Filter, '#call' do
2
+ subject { object.call(env) }
18
3
 
19
- it 'yields the expected values' do
20
- expect(subject.to_a).to eql(object.to_a)
21
- end
22
- end
23
-
24
- it 'should yield subjects' do
25
- expect { subject }.to change { yields }.from([]).to([subject_a])
26
- end
4
+ let(:object) { described_class.new(matcher, predicate) }
5
+ let(:matcher) { instance_double(Mutant::Matcher) }
6
+ let(:subject_a) { instance_double(Mutant::Subject) }
7
+ let(:subject_b) { instance_double(Mutant::Subject) }
8
+ let(:env) { instance_double(Mutant::Env) }
9
+ let(:predicate) { ->(node) { node.eql?(subject_a) } }
10
+
11
+ before do
12
+ expect(matcher).to receive(:call)
13
+ .with(env)
14
+ .and_return([subject_a, subject_b])
27
15
  end
28
16
 
29
- describe '.build' do
30
- subject { described_class.build(matcher, &predicate) }
31
-
32
- let(:predicate) { ->(_subject) { false } }
33
-
34
- its(:to_a) { should eql([]) }
17
+ it 'returns subjects after filtering' do
18
+ should eql([subject_a])
35
19
  end
36
20
  end
@@ -1,157 +1,113 @@
1
- RSpec.describe Mutant::Matcher::Method::Instance do
2
-
3
- let(:env) { Fixtures::TEST_ENV }
4
- let(:reporter) { Fixtures::TEST_CONFIG.reporter }
1
+ RSpec.describe Mutant::Matcher::Method::Instance, '#call' do
2
+ subject { object.call(env) }
3
+
4
+ let(:object) { described_class.new(scope, method) }
5
+ let(:env) { test_env }
6
+ let(:method_name) { :foo }
7
+ let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
8
+ let(:method) { scope.instance_method(method_name) }
9
+ let(:namespace) { self.class }
10
+ let(:type) { :def }
11
+ let(:method_arity) { 0 }
12
+ let(:base) { TestApp::InstanceMethodTests }
13
+
14
+ def name
15
+ node.children.fetch(0)
16
+ end
5
17
 
6
- describe '#each' do
7
- subject { object.each(&yields.method(:<<)) }
18
+ def arguments
19
+ node.children.fetch(1)
20
+ end
8
21
 
9
- let(:object) { described_class.build(env, scope, method) }
10
- let(:method) { scope.instance_method(method_name) }
11
- let(:yields) { [] }
12
- let(:namespace) { self.class }
13
- let(:type) { :def }
14
- let(:method_name) { :foo }
15
- let(:method_arity) { 0 }
16
- let(:base) { TestApp::InstanceMethodTests }
22
+ context 'when method is defined inside eval' do
23
+ let(:scope) { base::WithMemoizer }
24
+ let(:method) { scope.instance_method(:boz) }
25
+ let(:method_name) { :boz }
17
26
 
18
- def name
19
- node.children[0]
27
+ let(:expected_warnings) do
28
+ [
29
+ "#{method} does not have a valid source location, unable to emit subject"
30
+ ]
20
31
  end
21
32
 
22
- def arguments
23
- node.children[1]
24
- end
33
+ include_examples 'skipped candidate'
34
+ end
25
35
 
26
- context 'when method is defined without source location' do
27
- let(:scope) { Module }
28
- let(:method) { scope.instance_method(:object_id) }
29
-
30
- it 'does not emit matcher' do
31
- subject
32
- expect(yields.length).to be(0)
33
- end
34
-
35
- it 'does warn' do
36
- subject
37
- expect(reporter.warn_calls.last).to(
38
- eql("#{method.inspect} does not have valid source location unable to emit subject")
39
- )
40
- end
36
+ context 'when method is defined without source location' do
37
+ let(:scope) { Module }
38
+ let(:method) { scope.instance_method(:object_id) }
39
+
40
+ let(:expected_warnings) do
41
+ [
42
+ "#{method} does not have a valid source location, unable to emit subject"
43
+ ]
41
44
  end
42
45
 
43
- context 'when method is defined once' do
44
- let(:scope) { base::DefinedOnce }
45
- let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
46
- let(:method_line) { 10 }
46
+ include_examples 'skipped candidate'
47
+ end
47
48
 
48
- it_should_behave_like 'a method matcher'
49
+ context 'in module eval' do
50
+ let(:scope) { base::InModuleEval }
51
+
52
+ let(:expected_warnings) do
53
+ [
54
+ "#{method} is dynamically defined in a closure, unable to emit subject"
55
+ ]
49
56
  end
50
57
 
51
- context 'when method is defined once with a memoizer' do
52
- let(:scope) { base::WithMemoizer }
53
- let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
54
- let(:method_line) { 15 }
58
+ include_examples 'skipped candidate'
59
+ end
60
+
61
+ context 'in class eval' do
62
+ let(:scope) { base::InClassEval }
55
63
 
56
- it_should_behave_like 'a method matcher'
64
+ let(:expected_warnings) do
65
+ [
66
+ "#{method} is dynamically defined in a closure, unable to emit subject"
67
+ ]
57
68
  end
58
69
 
59
- context 'when method is defined multiple times' do
60
- context 'on different lines' do
61
- let(:scope) { base::DefinedMultipleTimes::DifferentLines }
62
- let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
63
- let(:method_line) { 24 }
64
- let(:method_arity) { 1 }
65
-
66
- it_should_behave_like 'a method matcher'
67
- end
68
-
69
- context 'on the same line' do
70
- let(:scope) { base::DefinedMultipleTimes::SameLineSameScope }
71
- let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
72
- let(:method_line) { 29 }
73
- let(:method_arity) { 1 }
74
-
75
- it_should_behave_like 'a method matcher'
76
- end
77
-
78
- context 'on the same line with different scope' do
79
- let(:scope) { base::DefinedMultipleTimes::SameLineDifferentScope }
80
- let(:source_path) { MutantSpec::ROOT.join('test_app/lib/test_app.rb') }
81
- let(:method_line) { 33 }
82
- let(:method_arity) { 1 }
83
-
84
- it_should_behave_like 'a method matcher'
85
- end
86
-
87
- context 'in module eval' do
88
- let(:scope) { base::InModuleEval }
89
-
90
- it 'does not emit matcher' do
91
- subject
92
- expect(yields.length).to be(0)
93
- end
94
-
95
- it 'does warn' do
96
- subject
97
- expect(reporter.warn_calls.last).to(
98
- eql("#{method.inspect} is defined from a 3rd party lib unable to emit subject")
99
- )
100
- end
101
- end
102
-
103
- context 'in class eval' do
104
- let(:scope) { base::InClassEval }
105
-
106
- it 'does not emit matcher' do
107
- subject
108
- expect(yields.length).to be(0)
109
- end
110
-
111
- it 'does warn' do
112
- subject
113
- expect(reporter.warn_calls.last).to(
114
- eql("#{method.inspect} is defined from a 3rd party lib unable to emit subject")
115
- )
116
- end
117
- end
118
- end
70
+ include_examples 'skipped candidate'
119
71
  end
120
72
 
121
- describe '.build' do
122
- let(:object) { described_class }
73
+ context 'when method is defined once' do
74
+ let(:method_name) { :bar }
75
+ let(:scope) { base::WithMemoizer }
76
+ let(:method_line) { 13 }
123
77
 
124
- subject { object.build(env, scope, method) }
78
+ it_should_behave_like 'a method matcher'
79
+ end
125
80
 
126
- let(:scope) do
127
- Class.new do
128
- include Adamantium
81
+ context 'when method is defined once with a memoizer' do
82
+ let(:scope) { base::WithMemoizer }
83
+ let(:method_line) { 15 }
129
84
 
130
- def foo
131
- end
132
- memoize :foo
85
+ it_should_behave_like 'a method matcher'
86
+ end
133
87
 
134
- def bar
135
- end
136
- end
137
- end
88
+ context 'when method is defined multiple times' do
89
+ context 'on different lines' do
90
+ let(:scope) { base::DefinedMultipleTimes::DifferentLines }
91
+ let(:method_line) { 24 }
92
+ let(:method_arity) { 1 }
138
93
 
139
- let(:method) do
140
- scope.instance_method(method_name)
94
+ it_should_behave_like 'a method matcher'
141
95
  end
142
96
 
143
- context 'with adamantium infected scope' do
144
- context 'with unmemoized method' do
145
- let(:method_name) { :bar }
97
+ context 'on the same line' do
98
+ let(:scope) { base::DefinedMultipleTimes::SameLineSameScope }
99
+ let(:method_line) { 29 }
100
+ let(:method_arity) { 1 }
146
101
 
147
- it { should eql(described_class.new(env, scope, method)) }
148
- end
102
+ it_should_behave_like 'a method matcher'
103
+ end
149
104
 
150
- context 'with memoized method' do
151
- let(:method_name) { :foo }
105
+ context 'on the same line with different scope' do
106
+ let(:scope) { base::DefinedMultipleTimes::SameLineDifferentScope }
107
+ let(:method_line) { 33 }
108
+ let(:method_arity) { 1 }
152
109
 
153
- it { should eql(described_class::Memoized.new(env, scope, method)) }
154
- end
110
+ it_should_behave_like 'a method matcher'
155
111
  end
156
112
  end
157
113
  end