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
@@ -13,8 +13,10 @@ RSpec.describe Mutant::Matcher::Namespace, '#call' do
13
13
  [
14
14
  [Mutant::Matcher::Methods::Singleton, raw_scope_b, [subject_b]],
15
15
  [Mutant::Matcher::Methods::Instance, raw_scope_b, []],
16
+ [Mutant::Matcher::Methods::Metaclass, raw_scope_b, []],
16
17
  [Mutant::Matcher::Methods::Singleton, raw_scope_a, [subject_a]],
17
- [Mutant::Matcher::Methods::Instance, raw_scope_a, []]
18
+ [Mutant::Matcher::Methods::Instance, raw_scope_a, []],
19
+ [Mutant::Matcher::Methods::Metaclass, raw_scope_a, []]
18
20
  ].each do |klass, scope, subjects|
19
21
  matcher = instance_double(Mutant::Matcher)
20
22
  expect(matcher).to receive(:call).with(env).and_return(subjects)
@@ -6,8 +6,10 @@ RSpec.describe Mutant::Matcher::Scope, '#call' do
6
6
  let(:env) { instance_double(Mutant::Env) }
7
7
  let(:matcher_a) { instance_double(Mutant::Matcher) }
8
8
  let(:matcher_b) { instance_double(Mutant::Matcher) }
9
+ let(:matcher_c) { instance_double(Mutant::Matcher) }
9
10
  let(:subject_a) { instance_double(Mutant::Subject) }
10
11
  let(:subject_b) { instance_double(Mutant::Subject) }
12
+ let(:subject_c) { instance_double(Mutant::Subject) }
11
13
 
12
14
  subject { object.call(env) }
13
15
 
@@ -20,6 +22,10 @@ RSpec.describe Mutant::Matcher::Scope, '#call' do
20
22
  .with(scope)
21
23
  .and_return(matcher_b)
22
24
 
25
+ expect(Mutant::Matcher::Methods::Metaclass).to receive(:new)
26
+ .with(scope)
27
+ .and_return(matcher_c)
28
+
23
29
  expect(matcher_a).to receive(:call)
24
30
  .with(env)
25
31
  .and_return([subject_a])
@@ -27,9 +33,13 @@ RSpec.describe Mutant::Matcher::Scope, '#call' do
27
33
  expect(matcher_b).to receive(:call)
28
34
  .with(env)
29
35
  .and_return([subject_b])
36
+
37
+ expect(matcher_c).to receive(:call)
38
+ .with(env)
39
+ .and_return([subject_c])
30
40
  end
31
41
 
32
42
  it 'concatenates subjects from matched singleton and instance methods' do
33
- should eql([subject_a, subject_b])
43
+ should eql([subject_a, subject_b, subject_c])
34
44
  end
35
45
  end
@@ -10,9 +10,9 @@ RSpec.describe Mutant::Meta::Example do
10
10
  )
11
11
  end
12
12
 
13
- let(:file) { 'foo/bar.rb' }
14
- let(:node) { s(:true) }
15
- let(:mutation_nodes) { [s(:nil), s(:false)] }
13
+ let(:file) { 'foo/bar.rb' }
14
+ let(:node) { s(:true) }
15
+ let(:mutation_nodes) { [s(:false)] }
16
16
 
17
17
  let(:mutations) do
18
18
  mutation_nodes.map do |node|
@@ -41,12 +41,7 @@ RSpec.describe Mutant::Mutator::Node do
41
41
  end
42
42
 
43
43
  specify do
44
- expect(apply).to eql(
45
- [
46
- s(:and, s(:nil), s(:true)),
47
- s(:and, s(:true), s(:nil))
48
- ].to_set
49
- )
44
+ expect(apply).to eql([s(:and, s(:nil), s(:true))].to_set)
50
45
  end
51
46
  end
52
47
  end
@@ -16,15 +16,15 @@ RSpec.describe Mutant::Parallel::Driver do
16
16
  end
17
17
 
18
18
  let(:var_active_jobs) do
19
- instance_double(Mutant::Variable::IVar, 'active jobs')
19
+ instance_double(Variable::IVar, 'active jobs')
20
20
  end
21
21
 
22
22
  let(:var_final) do
23
- instance_double(Mutant::Variable::IVar, 'final')
23
+ instance_double(Variable::IVar, 'final')
24
24
  end
25
25
 
26
26
  let(:var_sink) do
27
- instance_double(Mutant::Variable::IVar, 'sink')
27
+ instance_double(Variable::IVar, 'sink')
28
28
  end
29
29
 
30
30
  subject do
@@ -64,7 +64,7 @@ RSpec.describe Mutant::Parallel::Driver do
64
64
  receiver: var_final,
65
65
  selector: :take_timeout,
66
66
  arguments: [timeout],
67
- reaction: { return: Mutant::Variable.const_get(:Result)::Timeout.new }
67
+ reaction: { return: Variable.const_get(:Result)::Timeout.new }
68
68
  },
69
69
  {
70
70
  receiver: var_active_jobs,
@@ -31,23 +31,23 @@ RSpec.describe Mutant::Parallel::Worker do
31
31
  end
32
32
 
33
33
  let(:var_active_jobs) do
34
- instance_double(Mutant::Variable::IVar, 'active jobs')
34
+ instance_double(Variable::IVar, 'active jobs')
35
35
  end
36
36
 
37
37
  let(:var_final) do
38
- instance_double(Mutant::Variable::IVar, 'final')
38
+ instance_double(Variable::IVar, 'final')
39
39
  end
40
40
 
41
41
  let(:var_running) do
42
- instance_double(Mutant::Variable::MVar, 'running')
42
+ instance_double(Variable::MVar, 'running')
43
43
  end
44
44
 
45
45
  let(:var_sink) do
46
- instance_double(Mutant::Variable::IVar, 'sink')
46
+ instance_double(Variable::IVar, 'sink')
47
47
  end
48
48
 
49
49
  let(:var_source) do
50
- instance_double(Mutant::Variable::IVar, 'source')
50
+ instance_double(Variable::IVar, 'source')
51
51
  end
52
52
 
53
53
  subject do
@@ -30,28 +30,28 @@ RSpec.describe Mutant::Parallel do
30
30
  end
31
31
 
32
32
  let(:var_active_jobs) do
33
- instance_double(Mutant::Variable::IVar, 'active jobs')
33
+ instance_double(Variable::IVar, 'active jobs')
34
34
  end
35
35
 
36
36
  let(:var_final) do
37
- instance_double(Mutant::Variable::IVar, 'final')
37
+ instance_double(Variable::IVar, 'final')
38
38
  end
39
39
 
40
40
  let(:var_running) do
41
- instance_double(Mutant::Variable::MVar, 'running')
41
+ instance_double(Variable::MVar, 'running')
42
42
  end
43
43
 
44
44
  let(:var_sink) do
45
- instance_double(Mutant::Variable::IVar, 'sink')
45
+ instance_double(Variable::IVar, 'sink')
46
46
  end
47
47
 
48
48
  let(:var_source) do
49
- instance_double(Mutant::Variable::IVar, 'source')
49
+ instance_double(Variable::IVar, 'source')
50
50
  end
51
51
 
52
52
  def ivar(value, **attributes)
53
53
  {
54
- receiver: Mutant::Variable::IVar,
54
+ receiver: Variable::IVar,
55
55
  selector: :new,
56
56
  arguments: [
57
57
  condition_variable: condition_variable,
@@ -63,7 +63,7 @@ RSpec.describe Mutant::Parallel do
63
63
  end
64
64
 
65
65
  def mvar(*arguments)
66
- ivar(*arguments).merge(receiver: Mutant::Variable::MVar)
66
+ ivar(*arguments).merge(receiver: Variable::MVar)
67
67
  end
68
68
 
69
69
  let(:raw_expectations) do
@@ -1,47 +1,74 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Mutant::Registry do
4
- let(:lookup) { object.lookup(type) }
5
- let(:object) { described_class.new }
6
4
  let(:mutator) { class_double(Mutant::Mutator) }
5
+ let(:object) { described_class.new }
7
6
 
8
- def register_mutator
9
- object.register(type, mutator)
10
- end
11
-
12
- context 'on registered type' do
13
- subject { register_mutator }
7
+ describe '#lookup' do
8
+ subject { object.lookup(type) }
14
9
 
15
- let(:type) { :true }
10
+ def register
11
+ object.register(type, mutator)
12
+ end
16
13
 
17
- before { subject }
14
+ context 'on known type' do
15
+ let(:type) { :true }
18
16
 
19
- it 'returns registered mutator' do
20
- expect(lookup).to be(mutator)
17
+ it 'returns registered' do
18
+ register
19
+ expect(subject).to be(mutator)
20
+ end
21
21
  end
22
22
 
23
- it_behaves_like 'a command method'
23
+ context 'on unknown type' do
24
+ let(:type) { :unknown }
24
25
 
25
- context 'when registered twice' do
26
- it 'fails upon registration' do
27
- expect { register_mutator }.to raise_error(described_class::RegistryError, 'Duplicate type registration: :true')
26
+ it 'returns genericm mutator' do
27
+ expect(subject).to be(Mutant::Mutator::Node::Generic)
28
28
  end
29
29
  end
30
30
  end
31
31
 
32
- context 'on unknown type' do
33
- let(:type) { :unknown }
32
+ describe '#register' do
33
+ subject { object.register(type, mutator) }
34
34
 
35
- it 'raises error' do
36
- expect { lookup }.to raise_error(described_class::RegistryError, 'No entry for: :unknown')
35
+ def lookup
36
+ subject.lookup(type)
37
37
  end
38
- end
39
38
 
40
- context 'when registering an invalid node type' do
41
- let(:type) { :invalid }
39
+ context 'on registered type' do
40
+ let(:type) { :true }
41
+
42
+ it_behaves_like 'a command method'
42
43
 
43
- it 'raises error' do
44
- expect { register_mutator }.to raise_error(described_class::RegistryError, 'Invalid type registration: :invalid')
44
+ it 'allows to lookup the mutator' do
45
+ subject
46
+ expect(lookup).to be(mutator)
47
+ end
48
+
49
+ context 'when registering twice' do
50
+ it 'fails upon registration' do
51
+ object.register(type, mutator)
52
+
53
+ expect { subject }
54
+ .to raise_error(
55
+ described_class::RegistryError,
56
+ 'Duplicate type registration: :true'
57
+ )
58
+ end
59
+ end
60
+ end
61
+
62
+ context 'when registering an invalid node type' do
63
+ let(:type) { :invalid }
64
+
65
+ it 'raises error' do
66
+ expect { subject }
67
+ .to raise_error(
68
+ described_class::RegistryError,
69
+ 'Invalid type registration: :invalid'
70
+ )
71
+ end
45
72
  end
46
73
  end
47
74
  end
@@ -13,7 +13,7 @@ describe Mutant::Repository::Diff::Ranges do
13
13
  Tempfile.open('new') do |new_file|
14
14
  new_file.write(new)
15
15
  new_file.flush
16
- # rubocop:disable Lint/UnneededSplatExpansion
16
+ # rubocop:disable Lint/RedundantSplatExpansion
17
17
  stdout, status = Open3.capture2(
18
18
  *%W[
19
19
  git
@@ -25,7 +25,7 @@ describe Mutant::Repository::Diff::Ranges do
25
25
  #{new_file.path}
26
26
  ]
27
27
  )
28
- # rubocop:enable Lint/UnneededSplatExpansion
28
+ # rubocop:enable Lint/RedundantSplatExpansion
29
29
 
30
30
  fail unless [0, 256].include?(status.to_i)
31
31
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Subject::Method::Metaclass do
4
+ let(:object) do
5
+ described_class.new(
6
+ context: context,
7
+ node: node,
8
+ warnings: warnings
9
+ )
10
+ end
11
+
12
+ let(:node) { s(:def, :foo, s(:args)) }
13
+ let(:warnings) { instance_double(Mutant::Warnings) }
14
+
15
+ let(:context) do
16
+ Mutant::Context.new(scope, instance_double(Pathname))
17
+ end
18
+
19
+ let(:scope) do
20
+ Class.new do
21
+ class << self
22
+ def foo; end
23
+
24
+ def name
25
+ 'Test'
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ describe '#expression' do
32
+ subject { object.expression }
33
+
34
+ it { should eql(parse_expression('Test.foo')) }
35
+
36
+ it_should_behave_like 'an idempotent method'
37
+ end
38
+
39
+ describe '#match_expression' do
40
+ subject { object.match_expressions }
41
+
42
+ it { should eql(%w[Test.foo Test*].map(&method(:parse_expression))) }
43
+
44
+ it_should_behave_like 'an idempotent method'
45
+ end
46
+
47
+ describe '#prepare' do
48
+
49
+ subject { object.prepare }
50
+
51
+ it 'undefines method on scope' do
52
+ expect { subject }.to change { scope.methods.include?(:foo) }.from(true).to(false)
53
+ end
54
+
55
+ it_should_behave_like 'a command method'
56
+ end
57
+
58
+ describe '#source' do
59
+ subject { object.source }
60
+
61
+ it { should eql("class << self\n def foo\n end\nend") }
62
+ end
63
+ end
@@ -105,5 +105,6 @@ module TestApp
105
105
  end
106
106
  end
107
107
 
108
+ require 'test_app/metaclasses'
108
109
  require 'test_app/literal'
109
110
  $VERBOSE = original
@@ -0,0 +1,108 @@
1
+ # frozen_string_literal: true
2
+
3
+ module TestApp
4
+ module MetaclassMethodTests
5
+ module DefinedOnSelf
6
+ class << self
7
+ def foo; end
8
+ end
9
+
10
+ # again this is a weird edge-case that's being checked for consistent
11
+ # behaviour, not something that people ought to be doing.
12
+ module InsideMetaclass
13
+ class << self
14
+ # some older versions of ruby don't have Object#singleton_class,
15
+ # this is just an implementation of that so we can grab
16
+ # InsideMetaclass.metaclass for use as the scope object
17
+ def metaclass
18
+ class << self
19
+ self
20
+ end
21
+ end
22
+
23
+ # InsideMetaclass.foo
24
+ def foo; end
25
+
26
+ class << self
27
+ # #<Class:InsideMetaclass>.foo
28
+ def foo; end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ module DefinedOnLvar
35
+ a = self
36
+ class << a
37
+ def foo; end
38
+ end
39
+ end
40
+
41
+ module DefinedOnConstant
42
+ module InsideNamespace
43
+ class << InsideNamespace
44
+ def foo; end
45
+ end
46
+ end
47
+
48
+ module OutsideNamespace
49
+ end
50
+
51
+ class << OutsideNamespace
52
+ def foo
53
+ end
54
+ end
55
+ end
56
+
57
+ module DefinedMultipleTimes
58
+ module DifferentLines
59
+ class << self
60
+ def foo
61
+ end
62
+
63
+ def foo(_arg)
64
+ end
65
+ end
66
+ end
67
+
68
+ module SameLine
69
+ module SameScope
70
+ class << self
71
+ def foo; end; def foo(_arg); end
72
+ end
73
+ end
74
+
75
+ module DifferentScope
76
+ class << self; def foo; end; end; class << DifferentScope; def foo(_arg); end; end; class << MetaclassMethodTests; def foo; end; end
77
+ end
78
+
79
+ module DifferentName
80
+ class << self; def foo; end; def bar(_arg); end; end
81
+ end
82
+ end
83
+ end
84
+
85
+ module NotActuallyInAMetaclass
86
+ class << self
87
+ # some older versions of ruby don't have Object#singleton_class,
88
+ # this is just an implementation of that so we can grab
89
+ # InsideMetaclass.metaclass for use as the scope object
90
+ def metaclass
91
+ class << self
92
+ self
93
+ end
94
+ end
95
+
96
+ # this is a very weird construction that I do not recommend.
97
+ # to access SomeClass you have to do
98
+ # NotActuallyInAMetaclass.singleton_class::SomeClass. Very weird
99
+ # This is only here so we can test that metaclass_receiver? correctly
100
+ # returns false
101
+ class SomeClass
102
+ def foo
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end