mutant 0.10.21 → 0.10.26
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mutant.rb +32 -13
- 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/expression/namespace.rb +1 -1
- data/lib/mutant/integration.rb +8 -2
- data/lib/mutant/isolation/fork.rb +4 -11
- 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 +10 -9
- 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 -1
- 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/argument.rb +2 -2
- data/lib/mutant/mutator/node/block.rb +5 -1
- data/lib/mutant/mutator/node/dynamic_literal.rb +1 -1
- data/lib/mutant/mutator/node/kwargs.rb +44 -0
- data/lib/mutant/mutator/node/literal/regex.rb +12 -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 +55 -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/selector.rb +1 -1
- data/lib/mutant/subject.rb +2 -4
- data/lib/mutant/subject/method/instance.rb +6 -45
- data/lib/mutant/timer.rb +2 -2
- 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 +39 -151
- data/lib/mutant/warnings.rb +0 -106
@@ -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,10 +13,12 @@ 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],
|
@@ -30,6 +32,7 @@ module Mutant
|
|
30
32
|
is_a?: %i[instance_of?],
|
31
33
|
kind_of?: %i[instance_of?],
|
32
34
|
map: %i[each],
|
35
|
+
match: %i[match?],
|
33
36
|
method: %i[public_method],
|
34
37
|
reverse_each: %i[each],
|
35
38
|
reverse_map: %i[map each],
|
@@ -40,13 +43,17 @@ module Mutant
|
|
40
43
|
to_i: %i[to_int],
|
41
44
|
to_s: %i[to_str],
|
42
45
|
values_at: %i[fetch_values]
|
43
|
-
)
|
46
|
+
}.freeze.tap { |hash| hash.values(&:freeze) }
|
44
47
|
|
45
|
-
RECEIVER_SELECTOR_REPLACEMENTS =
|
48
|
+
RECEIVER_SELECTOR_REPLACEMENTS = {
|
46
49
|
Date: {
|
47
50
|
parse: %i[jd civil strptime iso8601 rfc3339 xmlschema rfc2822 rfc822 httpdate jisx0301]
|
48
|
-
}
|
49
|
-
|
51
|
+
}.freeze
|
52
|
+
}.freeze
|
53
|
+
|
54
|
+
REGEXP_MATCH_METHODS = %i[=~ match match?].freeze
|
55
|
+
REGEXP_START_WITH_NODES = %i[regexp_bos_anchor regexp_literal_literal].freeze
|
56
|
+
REGEXP_END_WITH_NODES = %i[regexp_literal_literal regexp_eos_anchor].freeze
|
50
57
|
|
51
58
|
private
|
52
59
|
|
@@ -81,6 +88,8 @@ module Mutant
|
|
81
88
|
end
|
82
89
|
|
83
90
|
def emit_selector_specific_mutations
|
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,42 @@ module Mutant
|
|
90
99
|
emit_lambda_mutation
|
91
100
|
end
|
92
101
|
|
102
|
+
def emit_start_end_with_mutations # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength
|
103
|
+
return unless REGEXP_MATCH_METHODS.include?(selector) && arguments.one?
|
104
|
+
|
105
|
+
argument = Mutant::Util.one(arguments)
|
106
|
+
|
107
|
+
return unless argument.type.equal?(:regexp) && (
|
108
|
+
regexp_ast = AST::Regexp.expand_regexp_ast(argument)
|
109
|
+
)
|
110
|
+
|
111
|
+
regexp_children = regexp_ast.children
|
112
|
+
|
113
|
+
case regexp_children.map(&:type)
|
114
|
+
when REGEXP_START_WITH_NODES
|
115
|
+
emit_start_with(regexp_children)
|
116
|
+
when REGEXP_END_WITH_NODES
|
117
|
+
emit_end_with(regexp_children)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def emit_start_with(regexp_nodes)
|
122
|
+
literal = Mutant::Util.one(regexp_nodes.last.children)
|
123
|
+
emit_type(receiver, :start_with?, s(:str, literal))
|
124
|
+
end
|
125
|
+
|
126
|
+
def emit_end_with(regexp_nodes)
|
127
|
+
literal = Mutant::Util.one(regexp_nodes.first.children)
|
128
|
+
emit_type(receiver, :end_with?, s(:str, literal))
|
129
|
+
end
|
130
|
+
|
131
|
+
def emit_predicate_mutations
|
132
|
+
return unless selector.match?(/\?\z/) && !selector.equal?(:defined?)
|
133
|
+
|
134
|
+
emit(s(:true))
|
135
|
+
emit(s(:false))
|
136
|
+
end
|
137
|
+
|
93
138
|
def emit_array_mutation
|
94
139
|
return unless selector.equal?(:Array) && possible_kernel_method?
|
95
140
|
|
@@ -177,7 +222,11 @@ module Mutant
|
|
177
222
|
end
|
178
223
|
|
179
224
|
def emit_argument_propagation
|
180
|
-
|
225
|
+
return unless arguments.one?
|
226
|
+
|
227
|
+
argument = Mutant::Util.one(arguments)
|
228
|
+
|
229
|
+
emit_propagation(argument) unless n_kwargs?(argument)
|
181
230
|
end
|
182
231
|
|
183
232
|
def mutate_receiver
|
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
|
data/lib/mutant/parser.rb
CHANGED
data/lib/mutant/pipe.rb
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
module Procto
|
5
|
+
# Define the .call method on +host+
|
6
|
+
#
|
7
|
+
# @param [Object] host
|
8
|
+
# the hosting object
|
9
|
+
#
|
10
|
+
# @return [undefined]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
def self.included(host)
|
14
|
+
host.extend(ClassMethods)
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
def call(*arguments)
|
19
|
+
new(*arguments).call
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end # Procto
|
23
|
+
end # Unparser
|
@@ -5,13 +5,19 @@ module Mutant
|
|
5
5
|
class CLI
|
6
6
|
# CLI runner status printer base class
|
7
7
|
class Printer
|
8
|
-
include
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
include(
|
9
|
+
AbstractType,
|
10
|
+
Adamantium,
|
11
|
+
Concord.new(:output, :object),
|
12
|
+
Procto
|
13
|
+
)
|
12
14
|
|
13
15
|
private_class_method :new
|
14
16
|
|
17
|
+
def call
|
18
|
+
run
|
19
|
+
end
|
20
|
+
|
15
21
|
# Create delegators to object
|
16
22
|
#
|
17
23
|
# @return [undefined]
|
@@ -15,13 +15,13 @@ module Mutant
|
|
15
15
|
:test_subject_ratio
|
16
16
|
)
|
17
17
|
|
18
|
-
FORMATS =
|
18
|
+
FORMATS = [
|
19
19
|
[:info, 'Subjects: %s', :amount_subjects ],
|
20
20
|
[:info, 'Total-Tests: %s', :amount_total_tests ],
|
21
21
|
[:info, 'Selected-Tests: %s', :amount_selected_tests],
|
22
22
|
[:info, 'Tests/Subject: %0.2f avg', :test_subject_ratio ],
|
23
23
|
[:info, 'Mutations: %s', :amount_mutations ]
|
24
|
-
])
|
24
|
+
].each(&:freeze)
|
25
25
|
|
26
26
|
# Run printer
|
27
27
|
#
|
@@ -33,7 +33,7 @@ module Mutant
|
|
33
33
|
__send__(report, format, __send__(value))
|
34
34
|
end
|
35
35
|
end
|
36
|
-
end #
|
36
|
+
end # Env
|
37
37
|
end # Printer
|
38
38
|
end # CLI
|
39
39
|
end # Reporter
|
@@ -18,7 +18,7 @@ module Mutant
|
|
18
18
|
:runtime
|
19
19
|
)
|
20
20
|
|
21
|
-
FORMATS =
|
21
|
+
FORMATS = [
|
22
22
|
[:info, 'Results: %s', :amount_mutation_results],
|
23
23
|
[:info, 'Kills: %s', :amount_mutations_killed],
|
24
24
|
[:info, 'Alive: %s', :amount_mutations_alive ],
|
@@ -28,7 +28,7 @@ module Mutant
|
|
28
28
|
[:info, 'Overhead: %0.2f%%', :overhead_percent ],
|
29
29
|
[:info, 'Mutations/s: %0.2f', :mutations_per_second ],
|
30
30
|
[:status, 'Coverage: %0.2f%%', :coverage_percent ]
|
31
|
-
])
|
31
|
+
].each(&:freeze)
|
32
32
|
|
33
33
|
# Run printer
|
34
34
|
#
|