mutant 0.11.28 → 0.11.29
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.
- checksums.yaml +4 -4
- data/lib/mutant/ast.rb +8 -9
- data/lib/mutant/bootstrap.rb +39 -13
- data/lib/mutant/cli/command/environment/test.rb +38 -1
- data/lib/mutant/cli/command/environment.rb +11 -0
- data/lib/mutant/context.rb +31 -61
- data/lib/mutant/env.rb +8 -1
- data/lib/mutant/expression/method.rb +4 -1
- data/lib/mutant/expression/methods.rb +4 -1
- data/lib/mutant/expression/namespace.rb +4 -4
- data/lib/mutant/hooks.rb +1 -0
- data/lib/mutant/integration/null.rb +1 -0
- data/lib/mutant/integration.rb +5 -1
- data/lib/mutant/matcher/descendants.rb +1 -1
- data/lib/mutant/matcher/method/instance.rb +5 -4
- data/lib/mutant/matcher/method/metaclass.rb +1 -1
- data/lib/mutant/matcher/method/singleton.rb +1 -1
- data/lib/mutant/matcher/method.rb +30 -4
- data/lib/mutant/matcher/methods.rb +8 -7
- data/lib/mutant/matcher/namespace.rb +1 -1
- data/lib/mutant/meta/example.rb +12 -2
- data/lib/mutant/mutation/runner/sink.rb +7 -3
- data/lib/mutant/mutation/runner.rb +2 -3
- data/lib/mutant/parallel/connection.rb +178 -0
- data/lib/mutant/parallel/pipe.rb +39 -0
- data/lib/mutant/parallel/worker.rb +42 -14
- data/lib/mutant/parallel.rb +18 -7
- data/lib/mutant/reporter/cli/format.rb +19 -2
- data/lib/mutant/reporter/cli/printer/test.rb +138 -0
- data/lib/mutant/reporter/cli.rb +33 -4
- data/lib/mutant/reporter.rb +22 -1
- data/lib/mutant/result.rb +53 -2
- data/lib/mutant/scope.rb +41 -1
- data/lib/mutant/subject/method/instance.rb +3 -2
- data/lib/mutant/subject/method/metaclass.rb +1 -1
- data/lib/mutant/subject/method/singleton.rb +2 -2
- data/lib/mutant/subject/method.rb +1 -1
- data/lib/mutant/test/runner/sink.rb +51 -0
- data/lib/mutant/test/runner.rb +62 -0
- data/lib/mutant/timer.rb +9 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/world.rb +2 -0
- data/lib/mutant.rb +7 -1
- metadata +9 -19
- data/lib/mutant/pipe.rb +0 -96
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e57360ec50ffdef54f132f4764c940caad83a2d3692ac812b95c236cd8ff52d
|
4
|
+
data.tar.gz: cc69f0948238d888f569caeee901dc9197b620a3693474323a0959212d73fc30
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf4a364cc90b650a6c9dff90b38fb22aaa54d62f98f3b85ae732894a112f89a72b7c6e81b25fdd051b4436e8b55c58203fa4645a1c471cd5745fd665c7f0418b
|
7
|
+
data.tar.gz: 27a2195e3cd277816e37970fbbf66ed3d4f5237d9be667345229a9739deebaa45366914c71ce41254b7e0a65ea3e40af6012ddf4f8d654164d5eab904345dcf0
|
data/lib/mutant/ast.rb
CHANGED
@@ -8,12 +8,12 @@ module Mutant
|
|
8
8
|
)
|
9
9
|
|
10
10
|
class View
|
11
|
-
include Adamantium, Anima.new(:node, :
|
11
|
+
include Adamantium, Anima.new(:node, :stack)
|
12
12
|
end
|
13
13
|
|
14
14
|
def on_line(line)
|
15
|
-
line_map.fetch(line, EMPTY_HASH).map do |node,
|
16
|
-
View.new(node: node,
|
15
|
+
line_map.fetch(line, EMPTY_HASH).map do |node, stack|
|
16
|
+
View.new(node: node, stack: stack)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
@@ -22,21 +22,20 @@ module Mutant
|
|
22
22
|
def line_map
|
23
23
|
line_map = {}
|
24
24
|
|
25
|
-
walk_path(node) do |node,
|
25
|
+
walk_path(node, []) do |node, stack|
|
26
26
|
expression = node.location.expression || next
|
27
|
-
(line_map[expression.line] ||= []) << [node,
|
27
|
+
(line_map[expression.line] ||= []) << [node, stack]
|
28
28
|
end
|
29
29
|
|
30
30
|
line_map
|
31
31
|
end
|
32
32
|
memoize :line_map
|
33
33
|
|
34
|
-
def walk_path(node, stack
|
35
|
-
block.call(node, stack
|
34
|
+
def walk_path(node, stack, &block)
|
35
|
+
block.call(node, stack)
|
36
|
+
stack = [*stack, node]
|
36
37
|
node.children.grep(::Parser::AST::Node) do |child|
|
37
|
-
stack.push(child.type)
|
38
38
|
walk_path(child, stack, &block)
|
39
|
-
stack.pop
|
40
39
|
end
|
41
40
|
end
|
42
41
|
end # AST
|
data/lib/mutant/bootstrap.rb
CHANGED
@@ -20,7 +20,7 @@ module Mutant
|
|
20
20
|
'%<scope_class>s#name from: %<scope>s raised an error: %<exception>s'
|
21
21
|
|
22
22
|
CLASS_NAME_TYPE_MISMATCH_FORMAT =
|
23
|
-
'%<scope_class>s#name from: %<
|
23
|
+
'%<scope_class>s#name from: %<raw_scope>s returned %<name>s'
|
24
24
|
|
25
25
|
private_constant(*constants(false))
|
26
26
|
|
@@ -47,6 +47,32 @@ module Mutant
|
|
47
47
|
selected_subjects.flat_map(&:mutations)
|
48
48
|
end
|
49
49
|
|
50
|
+
setup_integration(
|
51
|
+
env: env,
|
52
|
+
mutations: mutations,
|
53
|
+
selected_subjects: selected_subjects
|
54
|
+
)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
# rubocop:enable Metrics/MethodLength
|
58
|
+
|
59
|
+
# Run test only bootstrap
|
60
|
+
#
|
61
|
+
# @param [Env] env
|
62
|
+
#
|
63
|
+
# @return [Either<String, Env>]
|
64
|
+
def self.call_test(env)
|
65
|
+
env.record(:bootstrap) do
|
66
|
+
setup_integration(
|
67
|
+
env: load_hooks(env),
|
68
|
+
mutations: [],
|
69
|
+
selected_subjects: []
|
70
|
+
)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.setup_integration(env:, mutations:, selected_subjects:)
|
75
|
+
env.record(__method__) do
|
50
76
|
Integration.setup(env).fmap do |integration|
|
51
77
|
env.with(
|
52
78
|
integration: integration,
|
@@ -57,7 +83,7 @@ module Mutant
|
|
57
83
|
end
|
58
84
|
end
|
59
85
|
end
|
60
|
-
|
86
|
+
private_class_method :setup_integration
|
61
87
|
|
62
88
|
def self.load_hooks(env)
|
63
89
|
env.record(__method__) do
|
@@ -113,9 +139,9 @@ module Mutant
|
|
113
139
|
env.record(__method__) do
|
114
140
|
config = env.config
|
115
141
|
|
116
|
-
scopes = env.world.object_space.each_object(Module).with_object([]) do |
|
117
|
-
expression = expression(config.reporter, config.expression_parser,
|
118
|
-
aggregate << Scope.new(raw:
|
142
|
+
scopes = env.world.object_space.each_object(Module).with_object([]) do |raw_scope, aggregate|
|
143
|
+
expression = expression(config.reporter, config.expression_parser, raw_scope) || next
|
144
|
+
aggregate << Scope.new(raw: raw_scope, expression: expression)
|
119
145
|
end
|
120
146
|
|
121
147
|
scopes.sort_by { |scope| scope.expression.syntax }
|
@@ -123,31 +149,31 @@ module Mutant
|
|
123
149
|
end
|
124
150
|
private_class_method :matchable_scopes
|
125
151
|
|
126
|
-
def self.scope_name(reporter,
|
127
|
-
|
152
|
+
def self.scope_name(reporter, raw_scope)
|
153
|
+
raw_scope.name
|
128
154
|
rescue => exception
|
129
155
|
semantics_warning(
|
130
156
|
reporter,
|
131
157
|
CLASS_NAME_RAISED_EXCEPTION,
|
132
158
|
exception: exception.inspect,
|
133
|
-
scope:
|
134
|
-
scope_class:
|
159
|
+
scope: raw_scope,
|
160
|
+
scope_class: raw_scope.class
|
135
161
|
)
|
136
162
|
nil
|
137
163
|
end
|
138
164
|
private_class_method :scope_name
|
139
165
|
|
140
166
|
# rubocop:disable Metrics/MethodLength
|
141
|
-
def self.expression(reporter, expression_parser,
|
142
|
-
name = scope_name(reporter,
|
167
|
+
def self.expression(reporter, expression_parser, raw_scope)
|
168
|
+
name = scope_name(reporter, raw_scope) or return
|
143
169
|
|
144
170
|
unless name.instance_of?(String)
|
145
171
|
semantics_warning(
|
146
172
|
reporter,
|
147
173
|
CLASS_NAME_TYPE_MISMATCH_FORMAT,
|
148
174
|
name: name,
|
149
|
-
scope_class:
|
150
|
-
|
175
|
+
scope_class: raw_scope.class,
|
176
|
+
raw_scope: raw_scope
|
151
177
|
)
|
152
178
|
return
|
153
179
|
end
|
@@ -8,6 +8,21 @@ module Mutant
|
|
8
8
|
NAME = 'test'
|
9
9
|
SHORT_DESCRIPTION = 'test subcommands'
|
10
10
|
|
11
|
+
private
|
12
|
+
|
13
|
+
def parse_remaining_arguments(arguments)
|
14
|
+
arguments.each(&method(:add_integration_argument))
|
15
|
+
Either::Right.new(self)
|
16
|
+
end
|
17
|
+
|
18
|
+
def bootstrap
|
19
|
+
env = Env.empty(world, @config)
|
20
|
+
|
21
|
+
env
|
22
|
+
.record(:config) { Config.load(cli_config: @config, world: world) }
|
23
|
+
.bind { |config| Bootstrap.call_test(env.with(config: config)) }
|
24
|
+
end
|
25
|
+
|
11
26
|
class List < self
|
12
27
|
NAME = 'list'
|
13
28
|
SHORT_DESCRIPTION = 'List tests detected in the environment'
|
@@ -28,7 +43,29 @@ module Mutant
|
|
28
43
|
end
|
29
44
|
end
|
30
45
|
|
31
|
-
|
46
|
+
class Run < self
|
47
|
+
NAME = 'run'
|
48
|
+
SHORT_DESCRIPTION = 'Run tests'
|
49
|
+
SUBCOMMANDS = EMPTY_ARRAY
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def action
|
54
|
+
bootstrap
|
55
|
+
.bind(&Mutant::Test::Runner.public_method(:call))
|
56
|
+
.bind(&method(:from_result))
|
57
|
+
end
|
58
|
+
|
59
|
+
def from_result(result)
|
60
|
+
if result.success?
|
61
|
+
Either::Right.new(nil)
|
62
|
+
else
|
63
|
+
Either::Left.new('Test failures, exiting nonzero!')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
SUBCOMMANDS = [List, Run].freeze
|
32
69
|
end # Test
|
33
70
|
end # Environment
|
34
71
|
end # Command
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module Mutant
|
4
4
|
module CLI
|
5
5
|
class Command
|
6
|
+
# rubocop:disable Metrics/ClassLength
|
6
7
|
class Environment < self
|
7
8
|
NAME = 'environment'
|
8
9
|
SHORT_DESCRIPTION = 'Environment subcommands'
|
@@ -13,6 +14,7 @@ module Mutant
|
|
13
14
|
add_runner_options
|
14
15
|
add_integration_options
|
15
16
|
add_matcher_options
|
17
|
+
add_reporter_options
|
16
18
|
].freeze
|
17
19
|
|
18
20
|
private
|
@@ -126,7 +128,16 @@ module Mutant
|
|
126
128
|
set(mutation: @config.mutation.with(timeout: Float(number)))
|
127
129
|
end
|
128
130
|
end
|
131
|
+
|
132
|
+
def add_reporter_options(parser)
|
133
|
+
parser.separator('Reporting:')
|
134
|
+
|
135
|
+
parser.on('--print-warnings', 'Print warnings') do
|
136
|
+
set(reporter: @config.reporter.with(print_warnings: true))
|
137
|
+
end
|
138
|
+
end
|
129
139
|
end # Run
|
140
|
+
# rubocop:enable Metrics/ClassLength
|
130
141
|
end # Command
|
131
142
|
end # CLI
|
132
143
|
end # Mutant
|
data/lib/mutant/context.rb
CHANGED
@@ -3,83 +3,53 @@
|
|
3
3
|
module Mutant
|
4
4
|
# An abstract context where mutations can be applied to.
|
5
5
|
class Context
|
6
|
-
include Adamantium, Anima.new(:scope, :source_path)
|
7
|
-
extend AST::Sexp
|
6
|
+
include Adamantium, Anima.new(:constant_scope, :scope, :source_path)
|
8
7
|
|
9
|
-
|
8
|
+
class ConstantScope
|
9
|
+
include AST::Sexp
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
11
|
+
class Class < self
|
12
|
+
include Anima.new(:const, :descendant)
|
13
|
+
|
14
|
+
def call(node)
|
15
|
+
s(:class, const, nil, descendant.call(node))
|
16
|
+
end
|
17
17
|
end
|
18
|
-
end
|
19
18
|
|
20
|
-
|
21
|
-
|
22
|
-
# @return [String]
|
23
|
-
def identification
|
24
|
-
scope.name
|
25
|
-
end
|
19
|
+
class Module < self
|
20
|
+
include Anima.new(:const, :descendant)
|
26
21
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
# @param [Parser::AST::Node] node
|
31
|
-
#
|
32
|
-
# @return [Parser::AST::Class]
|
33
|
-
# if scope is of kind Class
|
34
|
-
#
|
35
|
-
# @return [Parser::AST::Module]
|
36
|
-
# if scope is of kind module
|
37
|
-
def self.wrap(scope, node)
|
38
|
-
name = s(:const, nil, scope.name.split(NAMESPACE_DELIMITER).last.to_sym)
|
39
|
-
case scope
|
40
|
-
when Class
|
41
|
-
s(:class, name, nil, node)
|
42
|
-
when Module
|
43
|
-
s(:module, name, node)
|
22
|
+
def call(node)
|
23
|
+
s(:module, const, descendant.call(node))
|
24
|
+
end
|
44
25
|
end
|
45
|
-
end
|
46
26
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
const = const.const_get(name)
|
27
|
+
class None < self
|
28
|
+
include Equalizer.new
|
29
|
+
|
30
|
+
def call(node)
|
31
|
+
node
|
32
|
+
end
|
54
33
|
end
|
55
34
|
end
|
56
|
-
memoize :nesting
|
57
35
|
|
58
|
-
|
59
|
-
|
60
|
-
# @return [String]
|
61
|
-
def unqualified_name
|
62
|
-
name_nesting.last
|
36
|
+
def match_expressions
|
37
|
+
scope.match_expressions
|
63
38
|
end
|
64
39
|
|
65
|
-
#
|
40
|
+
# Return root node for mutation
|
66
41
|
#
|
67
|
-
# @return [
|
68
|
-
def
|
69
|
-
|
70
|
-
Expression::Namespace::Recursive.new(
|
71
|
-
scope_name: name_nesting.take(index.succ).join(NAMESPACE_DELIMITER)
|
72
|
-
)
|
73
|
-
end
|
42
|
+
# @return [Parser::AST::Node]
|
43
|
+
def root(node)
|
44
|
+
constant_scope.call(node)
|
74
45
|
end
|
75
|
-
memoize :match_expressions
|
76
46
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
47
|
+
# Identification string
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
def identification
|
51
|
+
scope.raw.name
|
81
52
|
end
|
82
|
-
memoize :name_nesting
|
83
53
|
|
84
54
|
end # Context
|
85
55
|
end # Mutant
|
data/lib/mutant/env.rb
CHANGED
@@ -66,10 +66,18 @@ module Mutant
|
|
66
66
|
)
|
67
67
|
end
|
68
68
|
|
69
|
+
def run_test_index(test_index)
|
70
|
+
integration.call([integration.all_tests.fetch(test_index)])
|
71
|
+
end
|
72
|
+
|
69
73
|
def emit_mutation_worker_process_start(index:)
|
70
74
|
hooks.run(:mutation_worker_process_start, index: index)
|
71
75
|
end
|
72
76
|
|
77
|
+
def emit_test_worker_process_start(index:)
|
78
|
+
hooks.run(:test_worker_process_start, index: index)
|
79
|
+
end
|
80
|
+
|
73
81
|
# The test selections
|
74
82
|
#
|
75
83
|
# @return Hash{Mutation => Enumerable<Test>}
|
@@ -175,7 +183,6 @@ module Mutant
|
|
175
183
|
def timer
|
176
184
|
world.timer
|
177
185
|
end
|
178
|
-
|
179
186
|
end # Env
|
180
187
|
# rubocop:enable Metrics/ClassLength
|
181
188
|
end # Mutant
|
@@ -66,10 +66,10 @@ module Mutant
|
|
66
66
|
#
|
67
67
|
# @return [Matcher]
|
68
68
|
def matcher
|
69
|
-
|
69
|
+
raw_scope = find_raw_scope
|
70
70
|
|
71
|
-
if
|
72
|
-
Matcher::Scope.new(scope:
|
71
|
+
if raw_scope
|
72
|
+
Matcher::Scope.new(scope: Scope.new(expression: self, raw: raw_scope))
|
73
73
|
else
|
74
74
|
Matcher::Null.new
|
75
75
|
end
|
@@ -83,7 +83,7 @@ module Mutant
|
|
83
83
|
|
84
84
|
private
|
85
85
|
|
86
|
-
def
|
86
|
+
def find_raw_scope
|
87
87
|
Object.const_get(scope_name)
|
88
88
|
rescue NameError # rubocop:disable Lint/SuppressedException
|
89
89
|
end
|
data/lib/mutant/hooks.rb
CHANGED
data/lib/mutant/integration.rb
CHANGED
@@ -4,7 +4,11 @@ module Mutant
|
|
4
4
|
|
5
5
|
# Abstract base class mutant test framework integrations
|
6
6
|
class Integration
|
7
|
-
include AbstractType, Adamantium, Anima.new(
|
7
|
+
include AbstractType, Adamantium, Anima.new(
|
8
|
+
:arguments,
|
9
|
+
:expression_parser,
|
10
|
+
:world
|
11
|
+
)
|
8
12
|
|
9
13
|
LOAD_MESSAGE = <<~'MESSAGE'
|
10
14
|
Unable to load integration mutant-%<integration_name>s:
|
@@ -10,7 +10,7 @@ module Mutant
|
|
10
10
|
const = env.world.try_const_get(const_name) or return EMPTY_ARRAY
|
11
11
|
|
12
12
|
Chain.new(
|
13
|
-
matchers: matched_scopes(env, const).map { |scope| Scope.new(scope: scope
|
13
|
+
matchers: matched_scopes(env, const).map { |scope| Scope.new(scope: scope) }
|
14
14
|
).call(env)
|
15
15
|
end
|
16
16
|
|
@@ -8,7 +8,7 @@ module Mutant
|
|
8
8
|
|
9
9
|
# Dispatching builder, detects memoizable case
|
10
10
|
#
|
11
|
-
# @param [
|
11
|
+
# @param [Scope] scope
|
12
12
|
# @param [UnboundMethod] method
|
13
13
|
#
|
14
14
|
# @return [Matcher::Method::Instance]
|
@@ -31,7 +31,7 @@ module Mutant
|
|
31
31
|
# rubocop:enable Metrics/MethodLength
|
32
32
|
|
33
33
|
def self.memoized_method?(scope, method_name)
|
34
|
-
scope < Adamantium && scope.memoized?(method_name)
|
34
|
+
scope.raw < Adamantium && scope.raw.memoized?(method_name)
|
35
35
|
end
|
36
36
|
private_class_method :memoized_method?
|
37
37
|
|
@@ -48,9 +48,9 @@ module Mutant
|
|
48
48
|
end
|
49
49
|
|
50
50
|
def visibility
|
51
|
-
if scope.private_instance_methods.include?(method_name)
|
51
|
+
if scope.raw.private_instance_methods.include?(method_name)
|
52
52
|
:private
|
53
|
-
elsif scope.protected_instance_methods.include?(method_name)
|
53
|
+
elsif scope.raw.protected_instance_methods.include?(method_name)
|
54
54
|
:protected
|
55
55
|
else
|
56
56
|
:public
|
@@ -65,6 +65,7 @@ module Mutant
|
|
65
65
|
|
66
66
|
def source_location
|
67
67
|
scope
|
68
|
+
.raw
|
68
69
|
.unmemoized_instance_method(method_name)
|
69
70
|
.source_location
|
70
71
|
end
|
@@ -14,6 +14,11 @@ module Mutant
|
|
14
14
|
CLOSURE_WARNING_FORMAT =
|
15
15
|
'%s is dynamically defined in a closure, unable to emit subject'
|
16
16
|
|
17
|
+
CONSTANT_SCOPES = {
|
18
|
+
class: Context::ConstantScope::Class,
|
19
|
+
module: Context::ConstantScope::Module
|
20
|
+
}.freeze
|
21
|
+
|
17
22
|
# Matched subjects
|
18
23
|
#
|
19
24
|
# @param [Env] env
|
@@ -28,6 +33,8 @@ module Mutant
|
|
28
33
|
# Present to avoid passing the env argument around in case the
|
29
34
|
# logic would be implemented directly on the Matcher::Method
|
30
35
|
# instance
|
36
|
+
#
|
37
|
+
# rubocop:disable Metrics/ClassLength
|
31
38
|
class Evaluator
|
32
39
|
include(
|
33
40
|
AbstractType,
|
@@ -57,7 +64,7 @@ module Mutant
|
|
57
64
|
def match_view
|
58
65
|
return EMPTY_ARRAY if matched_view.nil?
|
59
66
|
|
60
|
-
if matched_view.
|
67
|
+
if matched_view.stack.any? { |node| node.type.equal?(:block) }
|
61
68
|
env.warn(CLOSURE_WARNING_FORMAT % target_method)
|
62
69
|
|
63
70
|
return EMPTY_ARRAY
|
@@ -80,7 +87,26 @@ module Mutant
|
|
80
87
|
end
|
81
88
|
|
82
89
|
def context
|
83
|
-
Context.new(scope: scope, source_path: source_path)
|
90
|
+
Context.new(constant_scope: constant_scope, scope: scope, source_path: source_path)
|
91
|
+
end
|
92
|
+
|
93
|
+
# rubocop:disable Metrics/MethodLength
|
94
|
+
def constant_scope
|
95
|
+
matched_view
|
96
|
+
.stack
|
97
|
+
.reverse
|
98
|
+
.reduce(Context::ConstantScope::None.new) do |descendant, node|
|
99
|
+
klass = CONSTANT_SCOPES[node.type]
|
100
|
+
|
101
|
+
if klass
|
102
|
+
klass.new(
|
103
|
+
const: node.children.fetch(0),
|
104
|
+
descendant: descendant
|
105
|
+
)
|
106
|
+
else
|
107
|
+
descendant
|
108
|
+
end
|
109
|
+
end
|
84
110
|
end
|
85
111
|
|
86
112
|
def ast
|
@@ -151,9 +177,9 @@ module Mutant
|
|
151
177
|
# end
|
152
178
|
#
|
153
179
|
# Change to this once 3.0 is EOL.
|
154
|
-
if scope.private_methods.include?(method_name)
|
180
|
+
if scope.raw.private_methods.include?(method_name)
|
155
181
|
:private
|
156
|
-
elsif scope.protected_methods.include?(method_name)
|
182
|
+
elsif scope.raw.protected_methods.include?(method_name)
|
157
183
|
:protected
|
158
184
|
else
|
159
185
|
:public
|
@@ -57,11 +57,11 @@ module Mutant
|
|
57
57
|
private
|
58
58
|
|
59
59
|
def access(_env, method_name)
|
60
|
-
scope.method(method_name)
|
60
|
+
scope.raw.method(method_name)
|
61
61
|
end
|
62
62
|
|
63
63
|
def candidate_scope
|
64
|
-
scope.singleton_class
|
64
|
+
scope.raw.singleton_class
|
65
65
|
end
|
66
66
|
|
67
67
|
end # Singleton
|
@@ -73,11 +73,11 @@ module Mutant
|
|
73
73
|
private
|
74
74
|
|
75
75
|
def access(_env, method_name)
|
76
|
-
scope.method(method_name)
|
76
|
+
scope.raw.method(method_name)
|
77
77
|
end
|
78
78
|
|
79
79
|
def candidate_scope
|
80
|
-
scope.singleton_class
|
80
|
+
scope.raw.singleton_class
|
81
81
|
end
|
82
82
|
end # Metaclass
|
83
83
|
|
@@ -105,18 +105,19 @@ module Mutant
|
|
105
105
|
private
|
106
106
|
|
107
107
|
# rubocop:disable Lint/RescueException
|
108
|
+
# mutant:disable - unstable source locations under < ruby-3.2
|
108
109
|
def access(env, method_name)
|
109
|
-
|
110
|
+
candidate_scope.instance_method(method_name)
|
110
111
|
rescue Exception => exception
|
111
112
|
env.warn(
|
112
|
-
MESSAGE % { scope: scope, method_name: method_name, exception: exception }
|
113
|
+
MESSAGE % { scope: scope, method_name: method_name, exception: exception.inspect }
|
113
114
|
)
|
114
115
|
nil
|
115
116
|
end
|
116
117
|
# rubocop:enable Lint/RescueException
|
117
118
|
|
118
119
|
def candidate_scope
|
119
|
-
scope
|
120
|
+
scope.raw
|
120
121
|
end
|
121
122
|
|
122
123
|
end # Instance
|