mutant 0.10.23 → 0.10.28
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.rb +34 -14
- data/lib/mutant/ast/find_metaclass_containing.rb +1 -1
- data/lib/mutant/ast/regexp.rb +54 -0
- data/lib/mutant/ast/regexp/transformer.rb +150 -0
- data/lib/mutant/ast/regexp/transformer/direct.rb +121 -0
- data/lib/mutant/ast/regexp/transformer/named_group.rb +50 -0
- data/lib/mutant/ast/regexp/transformer/options_group.rb +68 -0
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +92 -0
- data/lib/mutant/ast/regexp/transformer/recursive.rb +56 -0
- data/lib/mutant/ast/regexp/transformer/root.rb +28 -0
- data/lib/mutant/ast/regexp/transformer/text.rb +58 -0
- data/lib/mutant/ast/types.rb +115 -2
- data/lib/mutant/bootstrap.rb +1 -1
- data/lib/mutant/cli/command.rb +4 -0
- data/lib/mutant/cli/command/environment.rb +9 -3
- data/lib/mutant/cli/command/environment/subject.rb +0 -4
- data/lib/mutant/cli/command/environment/test.rb +36 -0
- data/lib/mutant/cli/command/root.rb +1 -1
- data/lib/mutant/config.rb +9 -55
- data/lib/mutant/config/coverage_criteria.rb +61 -0
- data/lib/mutant/context.rb +1 -1
- data/lib/mutant/env.rb +2 -2
- data/lib/mutant/expression.rb +0 -12
- data/lib/mutant/expression/method.rb +4 -4
- data/lib/mutant/expression/methods.rb +5 -4
- data/lib/mutant/integration.rb +8 -2
- data/lib/mutant/isolation/exception.rb +22 -0
- data/lib/mutant/isolation/fork.rb +9 -12
- data/lib/mutant/loader.rb +1 -1
- data/lib/mutant/matcher.rb +3 -3
- data/lib/mutant/matcher/config.rb +30 -8
- data/lib/mutant/matcher/method.rb +14 -13
- data/lib/mutant/matcher/method/instance.rb +6 -2
- data/lib/mutant/matcher/method/metaclass.rb +1 -1
- data/lib/mutant/matcher/methods.rb +2 -4
- data/lib/mutant/meta/example.rb +1 -1
- data/lib/mutant/meta/example/dsl.rb +6 -2
- data/lib/mutant/meta/example/verification.rb +1 -1
- data/lib/mutant/mutation.rb +1 -1
- data/lib/mutant/mutator.rb +8 -1
- data/lib/mutant/mutator/node.rb +0 -5
- data/lib/mutant/mutator/node/argument.rb +2 -2
- data/lib/mutant/mutator/node/dynamic_literal.rb +1 -1
- data/lib/mutant/mutator/node/index.rb +1 -0
- data/lib/mutant/mutator/node/kwargs.rb +2 -2
- data/lib/mutant/mutator/node/literal/float.rb +1 -3
- data/lib/mutant/mutator/node/literal/integer.rb +3 -6
- data/lib/mutant/mutator/node/literal/regex.rb +12 -0
- data/lib/mutant/mutator/node/module.rb +19 -0
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +3 -3
- data/lib/mutant/mutator/node/regexp.rb +20 -0
- data/lib/mutant/mutator/node/regexp/alternation_meta.rb +20 -0
- data/lib/mutant/mutator/node/regexp/beginning_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/capture_group.rb +25 -0
- data/lib/mutant/mutator/node/regexp/character_type.rb +31 -0
- data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/named_group.rb +39 -0
- data/lib/mutant/mutator/node/regexp/zero_or_more.rb +34 -0
- data/lib/mutant/mutator/node/regopt.rb +1 -1
- data/lib/mutant/mutator/node/sclass.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +73 -6
- data/lib/mutant/parallel.rb +2 -2
- data/lib/mutant/parallel/driver.rb +1 -1
- data/lib/mutant/parallel/worker.rb +1 -1
- data/lib/mutant/parser.rb +1 -1
- data/lib/mutant/pipe.rb +1 -1
- data/lib/mutant/procto.rb +23 -0
- data/lib/mutant/reporter/cli/printer.rb +10 -4
- data/lib/mutant/reporter/cli/printer/env.rb +3 -3
- data/lib/mutant/reporter/cli/printer/env_progress.rb +2 -2
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +3 -1
- data/lib/mutant/selector.rb +1 -1
- data/lib/mutant/subject.rb +2 -4
- data/lib/mutant/subject/method/instance.rb +6 -45
- data/lib/mutant/transform.rb +25 -0
- data/lib/mutant/variable.rb +322 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/world.rb +2 -3
- metadata +38 -149
- data/lib/mutant/warnings.rb +0 -106
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for root expression regexp wrapper
|
8
|
+
class RootExpression < Node
|
9
|
+
handle(:regexp_root_expression)
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
children.each_index(&method(:mutate_child))
|
15
|
+
end
|
16
|
+
end # RootExpression
|
17
|
+
end # Regexp
|
18
|
+
end # Node
|
19
|
+
end # Mutator
|
20
|
+
end # Mutant
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for pipe in `/foo|bar/` regexp
|
8
|
+
class AlternationMeta < Node
|
9
|
+
handle(:regexp_alternation_meta)
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
children.each_index(&method(:delete_child))
|
15
|
+
end
|
16
|
+
end # AlternationMeta
|
17
|
+
end # Regexp
|
18
|
+
end # Node
|
19
|
+
end # Mutator
|
20
|
+
end # Mutant
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for beginning of line anchor `^`
|
8
|
+
class BeginningOfLineAnchor < Node
|
9
|
+
handle(:regexp_bol_anchor)
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
emit(s(:regexp_bos_anchor))
|
15
|
+
end
|
16
|
+
end # BeginningOfLineAnchor
|
17
|
+
end # Regexp
|
18
|
+
end # Node
|
19
|
+
end # Mutator
|
20
|
+
end # Mutant
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for regexp capture groups, such as `/(foo)/`
|
8
|
+
class CaptureGroup < Node
|
9
|
+
handle(:regexp_capture_group)
|
10
|
+
|
11
|
+
children :group
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def dispatch
|
16
|
+
return unless group
|
17
|
+
|
18
|
+
emit(s(:regexp_passive_group, group))
|
19
|
+
emit_group_mutations
|
20
|
+
end
|
21
|
+
end # EndOfLineAnchor
|
22
|
+
end # Regexp
|
23
|
+
end # Node
|
24
|
+
end # Mutator
|
25
|
+
end # Mutant
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Character type mutator
|
8
|
+
class CharacterType < Node
|
9
|
+
map = {
|
10
|
+
regexp_digit_type: :regexp_nondigit_type,
|
11
|
+
regexp_hex_type: :regexp_nonhex_type,
|
12
|
+
regexp_space_type: :regexp_nonspace_type,
|
13
|
+
regexp_word_boundary_anchor: :regexp_nonword_boundary_anchor,
|
14
|
+
regexp_word_type: :regexp_nonword_type,
|
15
|
+
regexp_xgrapheme_type: :regexp_linebreak_type
|
16
|
+
}
|
17
|
+
|
18
|
+
MAP = map.merge(map.invert)
|
19
|
+
|
20
|
+
handle(*MAP.keys)
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def dispatch
|
25
|
+
emit(s(MAP.fetch(node.type)))
|
26
|
+
end
|
27
|
+
end # CharacterType
|
28
|
+
end # Regexp
|
29
|
+
end # Node
|
30
|
+
end # Mutator
|
31
|
+
end # Mutant
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for end of line anchor `$`
|
8
|
+
class EndOfLineAnchor < Node
|
9
|
+
handle(:regexp_eol_anchor)
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
emit(s(:regexp_eos_anchor))
|
15
|
+
end
|
16
|
+
end # EndOfLineAnchor
|
17
|
+
end # Regexp
|
18
|
+
end # Node
|
19
|
+
end # Mutator
|
20
|
+
end # Mutant
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for end of line or before end of string anchor `\Z`
|
8
|
+
class EndOfStringOrBeforeEndOfLineAnchor < Node
|
9
|
+
handle(:regexp_eos_ob_eol_anchor)
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def dispatch
|
14
|
+
emit(s(:regexp_eos_anchor))
|
15
|
+
end
|
16
|
+
end # EndOfStringOrBeforeEndOfLineAnchor
|
17
|
+
end # Regexp
|
18
|
+
end # Node
|
19
|
+
end # Mutator
|
20
|
+
end # Mutant
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for regexp named capture groups, such as `/(?<foo>bar)/`
|
8
|
+
class NamedGroup < Node
|
9
|
+
handle(:regexp_named_group)
|
10
|
+
|
11
|
+
children :name, :group
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
def dispatch
|
16
|
+
return unless group
|
17
|
+
|
18
|
+
emit_group_mutations
|
19
|
+
|
20
|
+
# Allows unused captures to be kept and named if they are explicitly prefixed with an
|
21
|
+
# underscore, like we allow with unused local variables.
|
22
|
+
return if name_underscored?
|
23
|
+
|
24
|
+
emit(s(:regexp_passive_group, group))
|
25
|
+
emit_name_underscore_mutation
|
26
|
+
end
|
27
|
+
|
28
|
+
def emit_name_underscore_mutation
|
29
|
+
emit_type("_#{name}", group)
|
30
|
+
end
|
31
|
+
|
32
|
+
def name_underscored?
|
33
|
+
name.start_with?('_')
|
34
|
+
end
|
35
|
+
end # EndOfLineAnchor
|
36
|
+
end # Regexp
|
37
|
+
end # Node
|
38
|
+
end # Mutator
|
39
|
+
end # Mutant
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
module Regexp
|
7
|
+
# Mutator for zero-or-more quantifier, `*`
|
8
|
+
class ZeroOrMore < Node
|
9
|
+
MAP = {
|
10
|
+
regexp_greedy_zero_or_more: :regexp_greedy_one_or_more,
|
11
|
+
regexp_reluctant_zero_or_more: :regexp_reluctant_one_or_more,
|
12
|
+
regexp_possessive_zero_or_more: :regexp_possessive_one_or_more
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
handle(*MAP.keys)
|
16
|
+
|
17
|
+
children :min, :max, :subject
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
# Replace:
|
22
|
+
# * `/a*/` with `/a+/`
|
23
|
+
# * `/a*?/` with `/a+?/`
|
24
|
+
# * `/a*+/` with `/a++/`
|
25
|
+
def dispatch
|
26
|
+
emit(s(MAP.fetch(node.type), *children))
|
27
|
+
emit_subject_mutations
|
28
|
+
emit(subject)
|
29
|
+
end
|
30
|
+
end # ZeroOrMore
|
31
|
+
end # Regexp
|
32
|
+
end # Node
|
33
|
+
end # Mutator
|
34
|
+
end # Mutant
|
@@ -13,23 +13,25 @@ module Mutant
|
|
13
13
|
|
14
14
|
children :receiver, :selector
|
15
15
|
|
16
|
-
SELECTOR_REPLACEMENTS =
|
16
|
+
SELECTOR_REPLACEMENTS = {
|
17
17
|
:< => %i[== eql? equal?],
|
18
18
|
:<= => %i[< == eql? equal?],
|
19
19
|
:== => %i[eql? equal?],
|
20
|
+
:=== => %i[is_a?],
|
21
|
+
:=~ => %i[match?],
|
20
22
|
:> => %i[== eql? equal?],
|
21
23
|
:>= => %i[> == eql? equal?],
|
22
24
|
__send__: %i[public_send],
|
23
25
|
all?: %i[any?],
|
24
26
|
any?: %i[all?],
|
25
27
|
at: %i[fetch key?],
|
26
|
-
eql?: %i[equal?],
|
27
28
|
fetch: %i[key?],
|
28
29
|
flat_map: %i[map],
|
29
30
|
gsub: %i[sub],
|
30
31
|
is_a?: %i[instance_of?],
|
31
32
|
kind_of?: %i[instance_of?],
|
32
33
|
map: %i[each],
|
34
|
+
match: %i[match?],
|
33
35
|
method: %i[public_method],
|
34
36
|
reverse_each: %i[each],
|
35
37
|
reverse_map: %i[map each],
|
@@ -40,13 +42,17 @@ module Mutant
|
|
40
42
|
to_i: %i[to_int],
|
41
43
|
to_s: %i[to_str],
|
42
44
|
values_at: %i[fetch_values]
|
43
|
-
)
|
45
|
+
}.freeze.tap { |hash| hash.values(&:freeze) }
|
44
46
|
|
45
|
-
RECEIVER_SELECTOR_REPLACEMENTS =
|
47
|
+
RECEIVER_SELECTOR_REPLACEMENTS = {
|
46
48
|
Date: {
|
47
49
|
parse: %i[jd civil strptime iso8601 rfc3339 xmlschema rfc2822 rfc822 httpdate jisx0301]
|
48
|
-
}
|
49
|
-
|
50
|
+
}.freeze
|
51
|
+
}.freeze
|
52
|
+
|
53
|
+
REGEXP_MATCH_METHODS = %i[=~ match match?].freeze
|
54
|
+
REGEXP_START_WITH_NODES = %i[regexp_bos_anchor regexp_literal_literal].freeze
|
55
|
+
REGEXP_END_WITH_NODES = %i[regexp_literal_literal regexp_eos_anchor].freeze
|
50
56
|
|
51
57
|
private
|
52
58
|
|
@@ -81,6 +87,9 @@ module Mutant
|
|
81
87
|
end
|
82
88
|
|
83
89
|
def emit_selector_specific_mutations
|
90
|
+
emit_reduce_to_sum_mutation
|
91
|
+
emit_start_end_with_mutations
|
92
|
+
emit_predicate_mutations
|
84
93
|
emit_array_mutation
|
85
94
|
emit_static_send
|
86
95
|
emit_const_get_mutation
|
@@ -90,6 +99,57 @@ module Mutant
|
|
90
99
|
emit_lambda_mutation
|
91
100
|
end
|
92
101
|
|
102
|
+
def emit_reduce_to_sum_mutation
|
103
|
+
return unless selector.equal?(:reduce)
|
104
|
+
|
105
|
+
reducer = arguments.last
|
106
|
+
|
107
|
+
return unless reducer.eql?(s(:sym, :+)) || reducer.eql?(s(:block_pass, s(:sym, :+)))
|
108
|
+
|
109
|
+
if arguments.length > 1
|
110
|
+
initial_value = arguments.first
|
111
|
+
emit_type(receiver, :sum, initial_value)
|
112
|
+
else
|
113
|
+
emit_type(receiver, :sum)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def emit_start_end_with_mutations # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
118
|
+
return unless REGEXP_MATCH_METHODS.include?(selector) && arguments.one?
|
119
|
+
|
120
|
+
argument = Mutant::Util.one(arguments)
|
121
|
+
|
122
|
+
return unless argument.type.equal?(:regexp) && (
|
123
|
+
regexp_ast = AST::Regexp.expand_regexp_ast(argument)
|
124
|
+
)
|
125
|
+
|
126
|
+
regexp_children = regexp_ast.children
|
127
|
+
|
128
|
+
case regexp_children.map(&:type)
|
129
|
+
when REGEXP_START_WITH_NODES
|
130
|
+
emit_start_with(regexp_children)
|
131
|
+
when REGEXP_END_WITH_NODES
|
132
|
+
emit_end_with(regexp_children)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def emit_start_with(regexp_nodes)
|
137
|
+
literal = Mutant::Util.one(regexp_nodes.last.children)
|
138
|
+
emit_type(receiver, :start_with?, s(:str, literal))
|
139
|
+
end
|
140
|
+
|
141
|
+
def emit_end_with(regexp_nodes)
|
142
|
+
literal = Mutant::Util.one(regexp_nodes.first.children)
|
143
|
+
emit_type(receiver, :end_with?, s(:str, literal))
|
144
|
+
end
|
145
|
+
|
146
|
+
def emit_predicate_mutations
|
147
|
+
return unless selector.match?(/\?\z/) && !selector.equal?(:defined?)
|
148
|
+
|
149
|
+
emit(s(:true))
|
150
|
+
emit(s(:false))
|
151
|
+
end
|
152
|
+
|
93
153
|
def emit_array_mutation
|
94
154
|
return unless selector.equal?(:Array) && possible_kernel_method?
|
95
155
|
|
@@ -187,11 +247,18 @@ module Mutant
|
|
187
247
|
def mutate_receiver
|
188
248
|
return unless receiver
|
189
249
|
emit_implicit_self
|
250
|
+
emit_explicit_self
|
190
251
|
emit_receiver_mutations do |node|
|
191
252
|
!n_nil?(node)
|
192
253
|
end
|
193
254
|
end
|
194
255
|
|
256
|
+
def emit_explicit_self
|
257
|
+
return if UNARY_METHOD_OPERATORS.include?(selector)
|
258
|
+
|
259
|
+
emit_receiver(N_SELF) unless n_nil?(receiver)
|
260
|
+
end
|
261
|
+
|
195
262
|
def emit_implicit_self
|
196
263
|
emit_receiver(nil) if n_self?(receiver) && !(
|
197
264
|
KEYWORDS.include?(selector) ||
|
data/lib/mutant/parallel.rb
CHANGED
@@ -90,7 +90,7 @@ module Mutant
|
|
90
90
|
|
91
91
|
# Parallel run configuration
|
92
92
|
class Config
|
93
|
-
include Adamantium
|
93
|
+
include Adamantium, Anima.new(
|
94
94
|
:block,
|
95
95
|
:jobs,
|
96
96
|
:process_name,
|
@@ -102,7 +102,7 @@ module Mutant
|
|
102
102
|
|
103
103
|
# Parallel execution status
|
104
104
|
class Status
|
105
|
-
include Adamantium
|
105
|
+
include Adamantium, Anima.new(
|
106
106
|
:active_jobs,
|
107
107
|
:done,
|
108
108
|
:payload
|