mutant 0.9.4 → 0.9.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (183) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +121 -0
  3. data/Changelog.md +26 -0
  4. data/Gemfile +0 -15
  5. data/Gemfile.lock +47 -58
  6. data/Gemfile.shared +7 -0
  7. data/LICENSE +1 -1
  8. data/README.md +72 -23
  9. data/config/reek.yml +1 -0
  10. data/config/rubocop.yml +10 -3
  11. data/docs/commercial-support.md +14 -0
  12. data/lib/mutant.rb +5 -1
  13. data/lib/mutant/ast.rb +0 -9
  14. data/lib/mutant/ast/find_metaclass_containing.rb +48 -0
  15. data/lib/mutant/ast/meta/send.rb +0 -6
  16. data/lib/mutant/bootstrap.rb +0 -36
  17. data/lib/mutant/cli.rb +6 -50
  18. data/lib/mutant/color.rb +0 -3
  19. data/lib/mutant/config.rb +0 -8
  20. data/lib/mutant/context.rb +0 -3
  21. data/lib/mutant/diff.rb +0 -17
  22. data/lib/mutant/env.rb +0 -6
  23. data/lib/mutant/expression/method.rb +6 -6
  24. data/lib/mutant/expression/methods.rb +6 -6
  25. data/lib/mutant/expression/parser.rb +0 -6
  26. data/lib/mutant/integration.rb +0 -18
  27. data/lib/mutant/isolation/fork.rb +0 -22
  28. data/lib/mutant/license.rb +12 -1
  29. data/lib/mutant/matcher.rb +0 -14
  30. data/lib/mutant/matcher/config.rb +0 -11
  31. data/lib/mutant/matcher/method.rb +0 -31
  32. data/lib/mutant/matcher/method/instance.rb +0 -8
  33. data/lib/mutant/matcher/method/metaclass.rb +86 -0
  34. data/lib/mutant/matcher/method/singleton.rb +0 -25
  35. data/lib/mutant/matcher/methods.rb +17 -28
  36. data/lib/mutant/matcher/namespace.rb +0 -10
  37. data/lib/mutant/matcher/scope.rb +2 -4
  38. data/lib/mutant/meta.rb +1 -3
  39. data/lib/mutant/meta/example/dsl.rb +0 -21
  40. data/lib/mutant/meta/example/verification.rb +1 -21
  41. data/lib/mutant/mutation.rb +0 -3
  42. data/lib/mutant/mutator.rb +1 -29
  43. data/lib/mutant/mutator/node.rb +1 -66
  44. data/lib/mutant/mutator/node/and_asgn.rb +0 -3
  45. data/lib/mutant/mutator/node/argument.rb +0 -15
  46. data/lib/mutant/mutator/node/arguments.rb +0 -20
  47. data/lib/mutant/mutator/node/begin.rb +0 -3
  48. data/lib/mutant/mutator/node/binary.rb +0 -23
  49. data/lib/mutant/mutator/node/block.rb +0 -15
  50. data/lib/mutant/mutator/node/break.rb +0 -3
  51. data/lib/mutant/mutator/node/case.rb +0 -9
  52. data/lib/mutant/mutator/node/class.rb +0 -3
  53. data/lib/mutant/mutator/node/conditional_loop.rb +0 -3
  54. data/lib/mutant/mutator/node/const.rb +0 -3
  55. data/lib/mutant/mutator/node/define.rb +0 -11
  56. data/lib/mutant/mutator/node/defined.rb +0 -3
  57. data/lib/mutant/mutator/node/dstr.rb +0 -3
  58. data/lib/mutant/mutator/node/dsym.rb +0 -3
  59. data/lib/mutant/mutator/node/generic.rb +0 -51
  60. data/lib/mutant/mutator/node/if.rb +0 -12
  61. data/lib/mutant/mutator/node/index.rb +0 -27
  62. data/lib/mutant/mutator/node/kwbegin.rb +0 -3
  63. data/lib/mutant/mutator/node/literal.rb +0 -3
  64. data/lib/mutant/mutator/node/literal/array.rb +0 -6
  65. data/lib/mutant/mutator/node/literal/boolean.rb +0 -4
  66. data/lib/mutant/mutator/node/literal/float.rb +0 -9
  67. data/lib/mutant/mutator/node/literal/hash.rb +0 -9
  68. data/lib/mutant/mutator/node/literal/integer.rb +0 -9
  69. data/lib/mutant/mutator/node/literal/nil.rb +0 -3
  70. data/lib/mutant/mutator/node/literal/range.rb +0 -6
  71. data/lib/mutant/mutator/node/literal/regex.rb +0 -6
  72. data/lib/mutant/mutator/node/literal/string.rb +0 -3
  73. data/lib/mutant/mutator/node/literal/symbol.rb +0 -3
  74. data/lib/mutant/mutator/node/masgn.rb +0 -3
  75. data/lib/mutant/mutator/node/match_current_line.rb +0 -3
  76. data/lib/mutant/mutator/node/mlhs.rb +0 -3
  77. data/lib/mutant/mutator/node/named_value/access.rb +2 -14
  78. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +0 -9
  79. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +0 -6
  80. data/lib/mutant/mutator/node/next.rb +0 -3
  81. data/lib/mutant/mutator/node/noop.rb +0 -3
  82. data/lib/mutant/mutator/node/nthref.rb +0 -3
  83. data/lib/mutant/mutator/node/op_asgn.rb +0 -3
  84. data/lib/mutant/mutator/node/or_asgn.rb +0 -3
  85. data/lib/mutant/mutator/node/procarg_zero.rb +0 -3
  86. data/lib/mutant/mutator/node/regopt.rb +0 -6
  87. data/lib/mutant/mutator/node/resbody.rb +0 -6
  88. data/lib/mutant/mutator/node/rescue.rb +2 -19
  89. data/lib/mutant/mutator/node/return.rb +0 -3
  90. data/lib/mutant/mutator/node/sclass.rb +20 -0
  91. data/lib/mutant/mutator/node/send.rb +3 -62
  92. data/lib/mutant/mutator/node/send/attribute_assignment.rb +0 -9
  93. data/lib/mutant/mutator/node/send/binary.rb +0 -11
  94. data/lib/mutant/mutator/node/send/conditional.rb +0 -3
  95. data/lib/mutant/mutator/node/splat.rb +0 -3
  96. data/lib/mutant/mutator/node/super.rb +0 -3
  97. data/lib/mutant/mutator/node/when.rb +0 -19
  98. data/lib/mutant/mutator/node/yield.rb +0 -3
  99. data/lib/mutant/mutator/node/zsuper.rb +0 -3
  100. data/lib/mutant/mutator/util/array.rb +0 -6
  101. data/lib/mutant/mutator/util/symbol.rb +0 -3
  102. data/lib/mutant/parallel.rb +0 -13
  103. data/lib/mutant/parallel/driver.rb +0 -10
  104. data/lib/mutant/parallel/worker.rb +0 -22
  105. data/lib/mutant/registry.rb +2 -7
  106. data/lib/mutant/reporter/cli.rb +0 -5
  107. data/lib/mutant/reporter/cli/format.rb +1 -10
  108. data/lib/mutant/reporter/cli/printer.rb +0 -40
  109. data/lib/mutant/reporter/cli/printer/env_progress.rb +0 -15
  110. data/lib/mutant/reporter/cli/printer/isolation_result.rb +0 -18
  111. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -5
  112. data/lib/mutant/reporter/cli/printer/mutation_result.rb +0 -21
  113. data/lib/mutant/reporter/cli/printer/status_progressive.rb +0 -8
  114. data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -9
  115. data/lib/mutant/repository/diff.rb +1 -13
  116. data/lib/mutant/repository/diff/ranges.rb +0 -11
  117. data/lib/mutant/result.rb +0 -3
  118. data/lib/mutant/runner.rb +0 -18
  119. data/lib/mutant/runner/sink.rb +0 -5
  120. data/lib/mutant/subject.rb +0 -8
  121. data/lib/mutant/subject/method.rb +0 -3
  122. data/lib/mutant/subject/method/instance.rb +0 -5
  123. data/lib/mutant/subject/method/metaclass.rb +30 -0
  124. data/lib/mutant/transform.rb +0 -92
  125. data/lib/mutant/version.rb +1 -1
  126. data/lib/mutant/warnings.rb +0 -6
  127. data/lib/mutant/zombifier.rb +4 -34
  128. data/meta/and.rb +0 -2
  129. data/meta/array.rb +0 -3
  130. data/meta/begin.rb +0 -3
  131. data/meta/block.rb +0 -3
  132. data/meta/break.rb +0 -1
  133. data/meta/case.rb +0 -6
  134. data/meta/casgn.rb +0 -3
  135. data/meta/cvasgn.rb +0 -1
  136. data/meta/def.rb +0 -7
  137. data/meta/ensure.rb +0 -1
  138. data/meta/false.rb +0 -1
  139. data/meta/gvasgn.rb +0 -1
  140. data/meta/hash.rb +0 -4
  141. data/meta/if.rb +0 -5
  142. data/meta/ivasgn.rb +0 -1
  143. data/meta/kwbegin.rb +0 -1
  144. data/meta/lvasgn.rb +0 -1
  145. data/meta/match_current_line.rb +0 -1
  146. data/meta/next.rb +0 -1
  147. data/meta/or.rb +0 -2
  148. data/meta/regexp.rb +0 -1
  149. data/meta/rescue.rb +0 -6
  150. data/meta/sclass.rb +12 -0
  151. data/meta/send.rb +0 -4
  152. data/meta/true.rb +0 -1
  153. data/meta/until.rb +0 -1
  154. data/meta/while.rb +0 -2
  155. data/meta/yield.rb +0 -1
  156. data/mutant.gemspec +4 -3
  157. data/mutant.sh +12 -0
  158. data/spec/integrations.yml +3 -1
  159. data/spec/support/corpus.rb +3 -3
  160. data/spec/support/ruby_vm.rb +1 -2
  161. data/spec/support/shared_context.rb +3 -3
  162. data/spec/support/xspec.rb +2 -2
  163. data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +64 -0
  164. data/spec/unit/mutant/expression/methods_spec.rb +7 -2
  165. data/spec/unit/mutant/license_spec.rb +17 -5
  166. data/spec/unit/mutant/matcher/method/metaclass_spec.rb +108 -0
  167. data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +62 -0
  168. data/spec/unit/mutant/matcher/namespace_spec.rb +3 -1
  169. data/spec/unit/mutant/matcher/scope_spec.rb +11 -1
  170. data/spec/unit/mutant/meta/example_spec.rb +3 -3
  171. data/spec/unit/mutant/mutator/node_spec.rb +1 -6
  172. data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
  173. data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
  174. data/spec/unit/mutant/parallel_spec.rb +7 -7
  175. data/spec/unit/mutant/registry_spec.rb +52 -25
  176. data/spec/unit/mutant/repository/diff/ranges_spec.rb +2 -2
  177. data/spec/unit/mutant/subject/method/metaclass_spec.rb +63 -0
  178. data/test_app/lib/test_app.rb +1 -0
  179. data/test_app/lib/test_app/metaclasses.rb +108 -0
  180. metadata +43 -16
  181. data/.circleci/config.yml +0 -53
  182. data/lib/mutant/variable.rb +0 -282
  183. data/spec/unit/mutant/variable_spec.rb +0 -618
@@ -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
@@ -26,15 +26,16 @@ Gem::Specification.new do |gem|
26
26
  gem.add_runtime_dependency('anima', '~> 0.3.1')
27
27
  gem.add_runtime_dependency('ast', '~> 2.2')
28
28
  gem.add_runtime_dependency('concord', '~> 0.1.5')
29
- gem.add_runtime_dependency('diff-lcs', '~> 1.3')
29
+ gem.add_runtime_dependency('diff-lcs', '= 1.3')
30
30
  gem.add_runtime_dependency('equalizer', '~> 0.0.9')
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.6.5')
34
+ gem.add_runtime_dependency('parser', '~> 2.7.1')
35
35
  gem.add_runtime_dependency('procto', '~> 0.0.2')
36
36
  gem.add_runtime_dependency('unparser', '~> 0.4.6')
37
+ gem.add_runtime_dependency('variable', '~> 0.0.1')
37
38
 
38
- gem.add_development_dependency('devtools', '~> 0.1.23')
39
+ gem.add_development_dependency('devtools', '~> 0.1.25')
39
40
  gem.add_development_dependency('parallel', '~> 1.3')
40
41
  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*'
@@ -2,13 +2,14 @@
2
2
  - name: rubyspec
3
3
  namespace: Rubyspec
4
4
  repo_uri: 'https://github.com/ruby/rubyspec.git'
5
- repo_ref: 'origin/master'
5
+ repo_ref: 249a36c2e9fcddbb208a0d618d05f6bd9a64fd17
6
6
  integration: mspec
7
7
  mutation_coverage: false
8
8
  mutation_generation: true
9
9
  exclude:
10
10
  - command_line/fixtures/bad_syntax.rb
11
11
  - command_line/fixtures/freeze_flag_required_diff_enc.rb
12
+ - core/file/stat_spec.rb
12
13
  - core/kernel/shared/sprintf_encoding.rb
13
14
  - core/module/fixtures/autoload_empty.rb
14
15
  - core/module/fixtures/autoload_never_set.rb
@@ -26,6 +27,7 @@
26
27
  - language/predefined/fixtures/data_only.rb
27
28
  - language/source_encoding_spec.rb
28
29
  - library/base64/decode64_spec.rb
30
+ - library/cgi/escapeHTML_spec.rb
29
31
  - security/cve_2010_1330_spec.rb
30
32
  - name: regexp_parser
31
33
  namespace: Regexp
@@ -10,7 +10,7 @@ module MutantSpec
10
10
 
11
11
  # Namespace module for corpus testing
12
12
  #
13
- # rubocop:disable MethodLength
13
+ # rubocop:disable Metrics/MethodLength
14
14
  module Corpus
15
15
  TMP = ROOT.join('tmp').freeze
16
16
  EXCLUDE_GLOB_FORMAT = '{%s}'
@@ -22,7 +22,7 @@ module MutantSpec
22
22
  private_constant(*constants(false))
23
23
 
24
24
  # Project under corpus test
25
- # rubocop:disable ClassLength
25
+ # rubocop:disable Metrics/ClassLength
26
26
  class Project
27
27
  MUTEX = Mutex.new
28
28
 
@@ -259,7 +259,7 @@ module MutantSpec
259
259
  #
260
260
  # @param [Array<String>] arguments
261
261
  #
262
- # rubocop:disable GuardClause - guard clause without else does not make sense
262
+ # rubocop:disable Style/GuardClause - guard clause without else does not make sense
263
263
  def system(arguments)
264
264
  return if Kernel.system(*arguments)
265
265
 
@@ -26,8 +26,7 @@ module MutantSpec
26
26
  super(DEFAULTS.merge(attributes))
27
27
  end
28
28
 
29
- # rubocop:disable Naming/UncommunicativeMethodParamName
30
- def handle(vm, observation)
29
+ def handle(vm, observation) # rubocop:disable Naming/MethodParameterName
31
30
  unless match?(observation)
32
31
  fail "Unexpected event observation: #{observation.inspect}, expected #{inspect}"
33
32
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # rubocop:disable ModuleLength
3
+ # rubocop:disable Metrics/ModuleLength
4
4
  module SharedContext
5
5
  # Prepend an anonymous module with the new `with` method
6
6
  #
@@ -25,8 +25,8 @@ module SharedContext
25
25
  end
26
26
  end
27
27
 
28
- # rubocop:disable MethodLength
29
- # rubocop:disable AbcSize
28
+ # rubocop:disable Metrics/MethodLength
29
+ # rubocop:disable Metrics/AbcSize
30
30
  def setup_shared_context
31
31
  let(:mutation_a) { Mutant::Mutation::Evil.new(subject_a, mutation_a_node) }
32
32
  let(:mutation_a_node) { s(:false) }
@@ -93,7 +93,7 @@ module XSpec
93
93
  class MessageExpectation
94
94
  include Anima.new(:receiver, :selector, :arguments, :reaction)
95
95
 
96
- # rubocop:disable ParameterLists
96
+ # rubocop:disable Metrics/ParameterLists
97
97
  def self.parse(receiver:, selector:, arguments: [], reaction: nil)
98
98
  new(
99
99
  receiver: receiver,
@@ -152,7 +152,7 @@ module XSpec
152
152
  expectations.empty? or fail "unconsumed expectations:\n#{expectations.map(&:inspect).join("\n")}"
153
153
  end
154
154
 
155
- # rubocop:disable MethodLength
155
+ # rubocop:disable Metrics/MethodLength
156
156
  def self.verify(rspec_context, expectations)
157
157
  verifier = new(expectations)
158
158
 
@@ -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
@@ -89,7 +89,7 @@ RSpec.describe Mutant::License do
89
89
 
90
90
  expect(stderr)
91
91
  .to have_received(:puts)
92
- .with('[Mutant-License-Error]: Soft fail, continuing in 20 seconds')
92
+ .with('[Mutant-License-Error]: Soft fail, continuing in 40 seconds')
93
93
  .ordered
94
94
 
95
95
  expect(stderr)
@@ -104,7 +104,7 @@ RSpec.describe Mutant::License do
104
104
 
105
105
  expect(kernel)
106
106
  .to have_received(:sleep)
107
- .with(20)
107
+ .with(40)
108
108
  .ordered
109
109
  end
110
110
  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