mutant 0.9.6 → 0.9.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (184) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +121 -0
  3. data/.rubocop.yml +203 -0
  4. data/Changelog.md +26 -0
  5. data/Gemfile +0 -7
  6. data/Gemfile.lock +27 -87
  7. data/Gemfile.shared +7 -0
  8. data/README.md +88 -27
  9. data/config/reek.yml +1 -0
  10. data/lib/mutant.rb +4 -2
  11. data/lib/mutant/ast.rb +0 -9
  12. data/lib/mutant/ast/find_metaclass_containing.rb +48 -0
  13. data/lib/mutant/ast/meta/send.rb +0 -6
  14. data/lib/mutant/bootstrap.rb +0 -36
  15. data/lib/mutant/cli.rb +5 -49
  16. data/lib/mutant/config.rb +0 -8
  17. data/lib/mutant/context.rb +0 -3
  18. data/lib/mutant/env.rb +0 -6
  19. data/lib/mutant/expression/method.rb +6 -6
  20. data/lib/mutant/expression/methods.rb +6 -6
  21. data/lib/mutant/expression/parser.rb +0 -6
  22. data/lib/mutant/integration.rb +0 -18
  23. data/lib/mutant/isolation/fork.rb +0 -22
  24. data/lib/mutant/license.rb +11 -0
  25. data/lib/mutant/matcher.rb +0 -14
  26. data/lib/mutant/matcher/config.rb +0 -11
  27. data/lib/mutant/matcher/method.rb +0 -31
  28. data/lib/mutant/matcher/method/instance.rb +0 -8
  29. data/lib/mutant/matcher/method/metaclass.rb +86 -0
  30. data/lib/mutant/matcher/method/singleton.rb +0 -25
  31. data/lib/mutant/matcher/methods.rb +17 -28
  32. data/lib/mutant/matcher/namespace.rb +0 -10
  33. data/lib/mutant/matcher/scope.rb +2 -4
  34. data/lib/mutant/meta/example/dsl.rb +0 -21
  35. data/lib/mutant/meta/example/verification.rb +0 -20
  36. data/lib/mutant/mutation.rb +0 -3
  37. data/lib/mutant/mutator.rb +1 -29
  38. data/lib/mutant/mutator/node.rb +1 -66
  39. data/lib/mutant/mutator/node/and_asgn.rb +0 -3
  40. data/lib/mutant/mutator/node/argument.rb +0 -15
  41. data/lib/mutant/mutator/node/arguments.rb +0 -20
  42. data/lib/mutant/mutator/node/begin.rb +0 -3
  43. data/lib/mutant/mutator/node/binary.rb +0 -23
  44. data/lib/mutant/mutator/node/block.rb +0 -15
  45. data/lib/mutant/mutator/node/break.rb +0 -3
  46. data/lib/mutant/mutator/node/case.rb +0 -9
  47. data/lib/mutant/mutator/node/class.rb +0 -3
  48. data/lib/mutant/mutator/node/conditional_loop.rb +0 -3
  49. data/lib/mutant/mutator/node/const.rb +0 -3
  50. data/lib/mutant/mutator/node/define.rb +0 -11
  51. data/lib/mutant/mutator/node/defined.rb +0 -3
  52. data/lib/mutant/mutator/node/dstr.rb +0 -3
  53. data/lib/mutant/mutator/node/dsym.rb +0 -3
  54. data/lib/mutant/mutator/node/generic.rb +0 -67
  55. data/lib/mutant/mutator/node/if.rb +0 -12
  56. data/lib/mutant/mutator/node/index.rb +0 -27
  57. data/lib/mutant/mutator/node/kwbegin.rb +0 -3
  58. data/lib/mutant/mutator/node/literal.rb +0 -3
  59. data/lib/mutant/mutator/node/literal/array.rb +0 -6
  60. data/lib/mutant/mutator/node/literal/boolean.rb +0 -4
  61. data/lib/mutant/mutator/node/literal/float.rb +0 -9
  62. data/lib/mutant/mutator/node/literal/hash.rb +0 -9
  63. data/lib/mutant/mutator/node/literal/integer.rb +0 -9
  64. data/lib/mutant/mutator/node/literal/nil.rb +0 -3
  65. data/lib/mutant/mutator/node/literal/range.rb +4 -7
  66. data/lib/mutant/mutator/node/literal/regex.rb +0 -6
  67. data/lib/mutant/mutator/node/literal/string.rb +0 -3
  68. data/lib/mutant/mutator/node/literal/symbol.rb +0 -3
  69. data/lib/mutant/mutator/node/masgn.rb +0 -3
  70. data/lib/mutant/mutator/node/match_current_line.rb +0 -3
  71. data/lib/mutant/mutator/node/mlhs.rb +0 -3
  72. data/lib/mutant/mutator/node/named_value/access.rb +2 -14
  73. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +0 -9
  74. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +0 -6
  75. data/lib/mutant/mutator/node/next.rb +0 -3
  76. data/lib/mutant/mutator/node/noop.rb +0 -3
  77. data/lib/mutant/mutator/node/nthref.rb +0 -3
  78. data/lib/mutant/mutator/node/op_asgn.rb +0 -3
  79. data/lib/mutant/mutator/node/or_asgn.rb +0 -3
  80. data/lib/mutant/mutator/node/procarg_zero.rb +0 -3
  81. data/lib/mutant/mutator/node/regopt.rb +0 -6
  82. data/lib/mutant/mutator/node/resbody.rb +0 -6
  83. data/lib/mutant/mutator/node/rescue.rb +2 -19
  84. data/lib/mutant/mutator/node/return.rb +0 -3
  85. data/lib/mutant/mutator/node/sclass.rb +20 -0
  86. data/lib/mutant/mutator/node/send.rb +2 -61
  87. data/lib/mutant/mutator/node/send/attribute_assignment.rb +0 -9
  88. data/lib/mutant/mutator/node/send/binary.rb +0 -11
  89. data/lib/mutant/mutator/node/send/conditional.rb +0 -3
  90. data/lib/mutant/mutator/node/splat.rb +0 -3
  91. data/lib/mutant/mutator/node/super.rb +0 -3
  92. data/lib/mutant/mutator/node/when.rb +0 -19
  93. data/lib/mutant/mutator/node/yield.rb +0 -3
  94. data/lib/mutant/mutator/node/zsuper.rb +0 -3
  95. data/lib/mutant/mutator/util/array.rb +0 -6
  96. data/lib/mutant/mutator/util/symbol.rb +0 -3
  97. data/lib/mutant/parallel.rb +0 -13
  98. data/lib/mutant/parallel/driver.rb +0 -10
  99. data/lib/mutant/parallel/worker.rb +0 -22
  100. data/lib/mutant/registry.rb +2 -7
  101. data/lib/mutant/reporter/cli.rb +0 -5
  102. data/lib/mutant/reporter/cli/format.rb +0 -9
  103. data/lib/mutant/reporter/cli/printer.rb +2 -42
  104. data/lib/mutant/reporter/cli/printer/env_progress.rb +0 -15
  105. data/lib/mutant/reporter/cli/printer/isolation_result.rb +0 -18
  106. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -5
  107. data/lib/mutant/reporter/cli/printer/mutation_result.rb +1 -22
  108. data/lib/mutant/reporter/cli/printer/status_progressive.rb +0 -8
  109. data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -9
  110. data/lib/mutant/repository/diff.rb +1 -13
  111. data/lib/mutant/repository/diff/ranges.rb +0 -11
  112. data/lib/mutant/result.rb +0 -3
  113. data/lib/mutant/runner.rb +0 -18
  114. data/lib/mutant/runner/sink.rb +0 -5
  115. data/lib/mutant/subject.rb +0 -8
  116. data/lib/mutant/subject/method.rb +0 -3
  117. data/lib/mutant/subject/method/instance.rb +40 -6
  118. data/lib/mutant/subject/method/metaclass.rb +30 -0
  119. data/lib/mutant/transform.rb +0 -92
  120. data/lib/mutant/version.rb +1 -1
  121. data/lib/mutant/warnings.rb +0 -6
  122. data/lib/mutant/zombifier.rb +2 -34
  123. data/meta/and.rb +0 -2
  124. data/meta/array.rb +0 -3
  125. data/meta/begin.rb +0 -3
  126. data/meta/block.rb +0 -3
  127. data/meta/break.rb +0 -1
  128. data/meta/case.rb +0 -6
  129. data/meta/casgn.rb +0 -3
  130. data/meta/cvasgn.rb +0 -1
  131. data/meta/def.rb +0 -7
  132. data/meta/ensure.rb +0 -1
  133. data/meta/false.rb +0 -1
  134. data/meta/gvasgn.rb +0 -1
  135. data/meta/hash.rb +0 -4
  136. data/meta/if.rb +0 -5
  137. data/meta/ivasgn.rb +0 -1
  138. data/meta/kwbegin.rb +0 -1
  139. data/meta/lvasgn.rb +0 -1
  140. data/meta/match_current_line.rb +0 -1
  141. data/meta/next.rb +0 -1
  142. data/meta/or.rb +0 -2
  143. data/meta/range.rb +24 -0
  144. data/meta/regexp.rb +0 -1
  145. data/meta/rescue.rb +0 -6
  146. data/meta/sclass.rb +12 -0
  147. data/meta/send.rb +0 -4
  148. data/meta/true.rb +0 -1
  149. data/meta/until.rb +0 -1
  150. data/meta/while.rb +0 -2
  151. data/meta/yield.rb +0 -1
  152. data/mutant.gemspec +7 -4
  153. data/mutant.sh +12 -0
  154. data/spec/spec_helper.rb +37 -22
  155. data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +64 -0
  156. data/spec/unit/mutant/expression/methods_spec.rb +7 -2
  157. data/spec/unit/mutant/license_spec.rb +15 -3
  158. data/spec/unit/mutant/matcher/method/metaclass_spec.rb +108 -0
  159. data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +62 -0
  160. data/spec/unit/mutant/matcher/namespace_spec.rb +3 -1
  161. data/spec/unit/mutant/matcher/scope_spec.rb +11 -1
  162. data/spec/unit/mutant/meta/example_spec.rb +3 -3
  163. data/spec/unit/mutant/mutator/node_spec.rb +1 -6
  164. data/spec/unit/mutant/registry_spec.rb +52 -25
  165. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +1 -1
  166. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +2 -2
  167. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +12 -12
  168. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +1 -1
  169. data/spec/unit/mutant/reporter/cli/printer_spec.rb +4 -4
  170. data/spec/unit/mutant/reporter/cli_spec.rb +1 -1
  171. data/spec/unit/mutant/subject/method/instance_spec.rb +117 -22
  172. data/spec/unit/mutant/subject/method/metaclass_spec.rb +63 -0
  173. data/test_app/Gemfile.minitest +2 -0
  174. data/test_app/lib/test_app.rb +5 -0
  175. data/test_app/lib/test_app/metaclasses.rb +108 -0
  176. metadata +74 -25
  177. data/.circleci/config.yml +0 -53
  178. data/config/rubocop.yml +0 -205
  179. data/lib/mutant/color.rb +0 -43
  180. data/lib/mutant/diff.rb +0 -114
  181. data/spec/shared/base_behavior.rb +0 -45
  182. data/spec/support/test_app.rb +0 -7
  183. data/spec/support/warnings.yml +0 -6
  184. data/spec/unit/mutant/diff_spec.rb +0 -189
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ Mutant::Meta::Example.add :sclass do
4
+ source 'class << self; bar; end'
5
+
6
+ mutation 'class << self; nil; end'
7
+ mutation 'class << self; self; end'
8
+ end
9
+
10
+ Mutant::Meta::Example.add :sclass do
11
+ source 'class << self; end'
12
+ end
@@ -5,7 +5,6 @@ Mutant::Meta::Example.add :send do
5
5
 
6
6
  singleton_mutations
7
7
  mutation 'a == b'
8
- mutation 'a >= b'
9
8
  mutation 'a.eql?(b)'
10
9
  mutation 'a.equal?(b)'
11
10
  mutation 'nil > b'
@@ -90,7 +89,6 @@ Mutant::Meta::Example.add :send do
90
89
 
91
90
  singleton_mutations
92
91
  mutation 'a == b'
93
- mutation 'a <= b'
94
92
  mutation 'a.eql?(b)'
95
93
  mutation 'a.equal?(b)'
96
94
  mutation 'nil < b'
@@ -488,9 +486,7 @@ end
488
486
  mutation 'true'
489
487
  mutation 'false'
490
488
  mutation "false #{operator} false"
491
- mutation "nil #{operator} false"
492
489
  mutation "true #{operator} true"
493
- mutation "true #{operator} nil"
494
490
  end
495
491
  end
496
492
 
@@ -3,6 +3,5 @@
3
3
  Mutant::Meta::Example.add :true do
4
4
  source 'true'
5
5
 
6
- mutation 'nil'
7
6
  mutation 'false'
8
7
  end
@@ -8,7 +8,6 @@ Mutant::Meta::Example.add :until do
8
8
  mutation 'until true; foo; end'
9
9
  mutation 'until true; end'
10
10
  mutation 'until false; foo; bar; end'
11
- mutation 'until nil; foo; bar; end'
12
11
  mutation 'until true; foo; nil; end'
13
12
  mutation 'until true; foo; self; end'
14
13
  mutation 'until true; nil; bar; end'
@@ -10,7 +10,6 @@ Mutant::Meta::Example.add :while do
10
10
  mutation 'while true; foo; end'
11
11
  mutation 'while true; end'
12
12
  mutation 'while false; foo; bar; end'
13
- mutation 'while nil; foo; bar; end'
14
13
  mutation 'while true; foo; nil; end'
15
14
  mutation 'while true; nil; bar; end'
16
15
  mutation 'while true; raise; end'
@@ -22,5 +21,4 @@ Mutant::Meta::Example.add :while do
22
21
  singleton_mutations
23
22
  mutation 'while true; raise; end'
24
23
  mutation 'while false; end'
25
- mutation 'while nil; end'
26
24
  end
@@ -5,6 +5,5 @@ Mutant::Meta::Example.add :yield do
5
5
 
6
6
  singleton_mutations
7
7
  mutation 'yield false'
8
- mutation 'yield nil'
9
8
  mutation 'yield'
10
9
  end
@@ -31,11 +31,14 @@ Gem::Specification.new do |gem|
31
31
  gem.add_runtime_dependency('ice_nine', '~> 0.11.1')
32
32
  gem.add_runtime_dependency('memoizable', '~> 0.4.2')
33
33
  gem.add_runtime_dependency('mprelude', '~> 0.1.0')
34
- gem.add_runtime_dependency('parser', '~> 2.7.0.2')
34
+ gem.add_runtime_dependency('parser', '~> 2.7.1')
35
35
  gem.add_runtime_dependency('procto', '~> 0.0.2')
36
- gem.add_runtime_dependency('unparser', '~> 0.4.6')
36
+ gem.add_runtime_dependency('unparser', '~> 0.4.8')
37
37
  gem.add_runtime_dependency('variable', '~> 0.0.1')
38
38
 
39
- gem.add_development_dependency('devtools', '~> 0.1.25')
40
- gem.add_development_dependency('parallel', '~> 1.3')
39
+ gem.add_development_dependency('parallel', '~> 1.3')
40
+ gem.add_development_dependency('rspec', '~> 3.9')
41
+ gem.add_development_dependency('rspec-core', '~> 3.9')
42
+ gem.add_development_dependency('rspec-its', '~> 1.2.0')
43
+ gem.add_development_dependency('rubocop', '~> 0.79.0')
41
44
  end
@@ -0,0 +1,12 @@
1
+ #/usr/bin/bash -ex
2
+
3
+ bundle exec mutant \
4
+ --since HEAD~1 \
5
+ --zombie \
6
+ --ignore-subject Mutant::CLI#add_debug_options \
7
+ --ignore-subject Mutant::Mutator::Node::Argument#skip? \
8
+ --ignore-subject Mutant::Mutator::Node::ProcargZero#dispatch \
9
+ --ignore-subject Mutant::Mutator::Node::When#mutate_conditions \
10
+ --ignore-subject Mutant::Zombifier#call \
11
+ -- \
12
+ 'Mutant*'
@@ -1,31 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- if ENV['COVERAGE'] == 'true'
4
- require 'simplecov'
5
-
6
- SimpleCov.start do
7
- command_name 'spec:unit'
8
-
9
- add_filter 'config'
10
- add_filter 'spec'
11
- add_filter 'vendor'
12
- add_filter 'test_app'
13
- add_filter 'lib/mutant.rb' # simplecov bug not seeing default block is executed
14
-
15
- minimum_coverage 100
16
- end
17
- end
18
-
19
- require 'tempfile'
20
- require 'concord'
21
- require 'anima'
22
3
  require 'adamantium'
23
- require 'devtools/spec_helper'
24
- require 'unparser/cli'
4
+ require 'anima'
5
+ require 'concord'
25
6
  require 'mutant'
26
7
  require 'mutant/meta'
8
+ require 'rspec/its'
9
+ require 'timeout'
10
+ require 'tempfile'
11
+ require 'tmpdir'
12
+
13
+ require './spec/shared/framework_integration_behavior'
14
+ require './spec/shared/method_matcher_behavior'
15
+ require './spec/support/corpus'
16
+ require './spec/support/file_system'
17
+ require './spec/support/ruby_vm'
18
+ require './spec/support/shared_context'
19
+ require './spec/support/xspec'
27
20
 
28
- $LOAD_PATH << File.join(TestApp.root, 'lib')
21
+ $LOAD_PATH << File.expand_path('../test_app/lib', __dir__)
29
22
 
30
23
  require 'test_app'
31
24
 
@@ -67,6 +60,28 @@ module XSpecHelper
67
60
  end
68
61
  end # XSpecHelper
69
62
 
63
+ RSpec.configuration.around(file_path: %r{spec/unit}) do |example|
64
+ Timeout.timeout(1, &example)
65
+ end
66
+
67
+ RSpec.shared_examples_for 'a command method' do
68
+ it 'returns self' do
69
+ should equal(object)
70
+ end
71
+ end
72
+
73
+ RSpec.shared_examples_for 'an idempotent method' do
74
+ it 'is idempotent' do
75
+ first = subject
76
+ fail 'RSpec not configured for threadsafety' unless RSpec.configuration.threadsafe?
77
+ mutex = __memoized.instance_variable_get(:@mutex)
78
+ memoized = __memoized.instance_variable_get(:@memoized)
79
+
80
+ mutex.synchronize { memoized.delete(:subject) }
81
+ should equal(first)
82
+ end
83
+ end
84
+
70
85
  RSpec.configure do |config|
71
86
  config.extend(SharedContext)
72
87
  config.include(ParserHelper)
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::AST::FindMetaclassContaining do
4
+ describe '#call' do
5
+ subject { described_class.call(ast, node) }
6
+
7
+ let(:metaclass_node) { s(:sclass, s(:self), method_node) }
8
+ let(:method_node) { s(:def, 'test', s(:nil)) }
9
+
10
+ let(:ast) { metaclass_node }
11
+ let(:node) { method_node }
12
+
13
+ context 'when called without ast' do
14
+ let(:ast) { nil }
15
+
16
+ it { expect { subject }.to raise_error }
17
+ end
18
+
19
+ context 'when called without node' do
20
+ let(:node) { nil }
21
+
22
+ it { is_expected.to be nil }
23
+ end
24
+
25
+ context 'when called with ast which contains a duplicate of the node' do
26
+ let(:node) { s(:def, 'test', s(:nil)) }
27
+
28
+ shared_examples_for 'unfooled by the duplicate node' do
29
+ it { is_expected.to be nil }
30
+
31
+ # if we changed method_node or node without altering the other to match,
32
+ # the above example would provide a false positive. by ensuring node and
33
+ # method_node are eq but not equal, we ensure the usefulness of the
34
+ # above example.
35
+ it { expect(node).to eq(method_node) }
36
+ it { expect(node).not_to be method_node }
37
+ end
38
+
39
+ it_behaves_like 'unfooled by the duplicate node'
40
+
41
+ context 'when the node is in a begin block' do
42
+ let(:metaclass_node) { s(:sclass, s(:self), s(:begin, method_node)) }
43
+
44
+ it_behaves_like 'unfooled by the duplicate node'
45
+ end
46
+ end
47
+
48
+ context 'when called with ast containing the node' do
49
+ it { is_expected.to be metaclass_node }
50
+
51
+ context 'inside a begin block' do
52
+ let(:metaclass_node) { s(:sclass, s(:self), s(:begin, method_node)) }
53
+
54
+ it { is_expected.to be metaclass_node }
55
+ end
56
+
57
+ context 'inside a different class' do
58
+ let(:metaclass_node) { s(:sclass, s(:self), s(:class, :MyClass, nil, method_node)) }
59
+
60
+ it { is_expected.to be nil }
61
+ end
62
+ end
63
+ end
64
+ end
@@ -49,13 +49,18 @@ RSpec.describe Mutant::Expression::Methods do
49
49
  context 'with an instance method' do
50
50
  let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '#' } }
51
51
 
52
- it { should eql(Mutant::Matcher::Methods::Instance.new(TestApp::Literal)) }
52
+ it { should eql(Mutant::Matcher::Chain.new([Mutant::Matcher::Methods::Instance.new(TestApp::Literal)])) }
53
53
  end
54
54
 
55
55
  context 'with a singleton method' do
56
56
  let(:attributes) { { scope_name: 'TestApp::Literal', scope_symbol: '.' } }
57
57
 
58
- it { should eql(Mutant::Matcher::Methods::Singleton.new(TestApp::Literal)) }
58
+ it do
59
+ should eql(Mutant::Matcher::Chain.new([
60
+ Mutant::Matcher::Methods::Singleton.new(TestApp::Literal),
61
+ Mutant::Matcher::Methods::Metaclass.new(TestApp::Literal)
62
+ ]))
63
+ end
59
64
  end
60
65
  end
61
66
  end
@@ -283,11 +283,23 @@ RSpec.describe Mutant::License do
283
283
  context 'when mutant-license gem cannot be loaded' do
284
284
  let(:load_json) { false }
285
285
 
286
- before do
287
- allow(gem_method).to receive(:call).and_raise(Gem::LoadError, 'test-error')
286
+ def self.setup_error(message)
287
+ before do
288
+ allow(gem_method).to receive(:call).and_raise(Gem::LoadError, message)
289
+ end
290
+ end
291
+
292
+ context 'while the mutant license gem from rubygems is present' do
293
+ setup_error %{can't activate mutant-license (~> 0.1.0), already activated mutant-license-0.0.0.}
294
+
295
+ it_fails_with_message '[Mutant-License-Error]: mutant-license gem from rubygems.org is a dummy'
288
296
  end
289
297
 
290
- it_fails_with_message '[Mutant-License-Error]: test-error'
298
+ context 'with other error message' do
299
+ setup_error 'test-error'
300
+
301
+ it_fails_with_message '[Mutant-License-Error]: test-error'
302
+ end
291
303
  end
292
304
  end
293
305
  end
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Matcher::Method::Metaclass, '#call' do
4
+ SOURCE_PATH = 'test_app/lib/test_app/metaclasses.rb'
5
+ subject { object.call(env) }
6
+
7
+ let(:object) { described_class.new(scope, method) }
8
+ let(:method) { scope.method(method_name) }
9
+ let(:type) { :def }
10
+ let(:method_name) { :foo }
11
+ let(:method_arity) { 0 }
12
+ let(:base) { TestApp::MetaclassMethodTests }
13
+ let(:source_path) { MutantSpec::ROOT.join(SOURCE_PATH) }
14
+ let(:warnings) { instance_double(Mutant::Warnings) }
15
+
16
+ let(:world) do
17
+ instance_double(
18
+ Mutant::World,
19
+ pathname: Pathname,
20
+ warnings: warnings
21
+ )
22
+ end
23
+
24
+ let(:env) do
25
+ instance_double(
26
+ Mutant::Env,
27
+ config: Mutant::Config::DEFAULT,
28
+ parser: Fixtures::TEST_ENV.parser,
29
+ world: world
30
+ )
31
+ end
32
+
33
+ def name
34
+ node.children.fetch(0)
35
+ end
36
+
37
+ def arguments
38
+ node.children.fetch(1)
39
+ end
40
+
41
+ context 'when also defined on lvar' do
42
+ let(:scope) { base::DefinedOnLvar }
43
+ let(:expected_warnings) do
44
+ [
45
+ 'Can only match :def inside :sclass on :self or :const, got :sclass on :lvar unable to match'
46
+ ]
47
+ end
48
+
49
+ include_examples 'skipped candidate'
50
+ end
51
+
52
+ context 'when defined on self' do
53
+ let(:scope) { base::DefinedOnSelf }
54
+ let(:method_line) { 7 }
55
+
56
+ it_should_behave_like 'a method matcher'
57
+
58
+ context 'when scope is a metaclass' do
59
+ let(:scope) { base::DefinedOnSelf::InsideMetaclass.metaclass }
60
+ let(:method_line) { 28 }
61
+
62
+ it_should_behave_like 'a method matcher'
63
+ end
64
+ end
65
+
66
+ context 'when defined on constant' do
67
+ context 'inside namespace' do
68
+ let(:scope) { base::DefinedOnConstant::InsideNamespace }
69
+ let(:method_line) { 44 }
70
+
71
+ it_should_behave_like 'a method matcher'
72
+ end
73
+
74
+ context 'outside namespace' do
75
+ let(:scope) { base::DefinedOnConstant::OutsideNamespace }
76
+ let(:method_line) { 52 }
77
+
78
+ it_should_behave_like 'a method matcher'
79
+ end
80
+ end
81
+
82
+ context 'when defined multiple times in the same line' do
83
+ context 'with method on different scope' do
84
+ let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentScope }
85
+ let(:method_line) { 76 }
86
+ let(:method_arity) { 1 }
87
+
88
+ it_should_behave_like 'a method matcher'
89
+ end
90
+
91
+ context 'with different name' do
92
+ let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentName }
93
+ let(:method_line) { 80 }
94
+
95
+ it_should_behave_like 'a method matcher'
96
+ end
97
+ end
98
+
99
+ # tests that the evaluator correctly returns nil when the metaclass doesn't
100
+ # directly contain the method
101
+ context 'when defined inside a class in a metaclass' do
102
+ let(:scope) { base::NotActuallyInAMetaclass }
103
+ let(:method) { scope.metaclass::SomeClass.new.method(:foo) }
104
+ let(:method_line) { 93 }
105
+
106
+ it { is_expected.to be_empty }
107
+ end
108
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Matcher::Methods::Metaclass, '#call' do
4
+ let(:object) { described_class.new(class_under_test) }
5
+ let(:env) { Fixtures::TEST_ENV }
6
+
7
+ let(:class_under_test) do
8
+ parent = Module.new do
9
+ class << self
10
+ def method_d; end
11
+
12
+ protected
13
+
14
+ def method_e; end
15
+
16
+ private
17
+
18
+ def method_f; end
19
+ end
20
+ end
21
+
22
+ Class.new do
23
+ extend parent
24
+
25
+ class << self
26
+ def method_a; end
27
+
28
+ protected
29
+
30
+ def method_b; end
31
+
32
+ private
33
+
34
+ def method_c; end
35
+ end
36
+ end
37
+ end
38
+
39
+ let(:subject_a) { instance_double(Mutant::Subject, 'A') }
40
+ let(:subject_b) { instance_double(Mutant::Subject, 'B') }
41
+ let(:subject_c) { instance_double(Mutant::Subject, 'C') }
42
+
43
+ let(:subjects) { [subject_a, subject_b, subject_c] }
44
+
45
+ before do
46
+ matcher = Mutant::Matcher::Method::Metaclass
47
+
48
+ {
49
+ method_a: subject_a,
50
+ method_b: subject_b,
51
+ method_c: subject_c
52
+ }.each do |method, subject|
53
+ allow(matcher).to receive(:new)
54
+ .with(class_under_test, class_under_test.method(method))
55
+ .and_return(Mutant::Matcher::Static.new([subject]))
56
+ end
57
+ end
58
+
59
+ it 'returns expected subjects' do
60
+ expect(object.call(env)).to eql(subjects)
61
+ end
62
+ end