mutant 0.10.24 → 0.10.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.rb +15 -11
- data/lib/mutant/ast/find_metaclass_containing.rb +1 -1
- data/lib/mutant/ast/regexp.rb +17 -0
- data/lib/mutant/ast/regexp/transformer.rb +2 -2
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +4 -2
- data/lib/mutant/bootstrap.rb +1 -1
- data/lib/mutant/cli/command.rb +4 -0
- 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 +1 -1
- data/lib/mutant/context.rb +1 -1
- data/lib/mutant/env.rb +2 -2
- 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 +1 -1
- data/lib/mutant/matcher/config.rb +6 -3
- data/lib/mutant/matcher/method.rb +12 -10
- 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 +0 -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.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/literal/float.rb +1 -3
- data/lib/mutant/mutator/node/literal/integer.rb +3 -6
- data/lib/mutant/mutator/node/literal/range.rb +1 -1
- data/lib/mutant/mutator/node/literal/regex.rb +3 -17
- 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 +0 -11
- data/lib/mutant/mutator/node/regexp/beginning_of_line_anchor.rb +20 -0
- data/lib/mutant/mutator/node/regexp/character_type.rb +1 -1
- 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 +1 -1
- data/lib/mutant/subject/method/instance.rb +5 -42
- 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 +1 -1
- metadata +13 -160
- data/lib/mutant/mutator/node/regexp/greedy_zero_or_more.rb +0 -24
@@ -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
|
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
|
#
|
@@ -28,6 +28,7 @@ module Mutant
|
|
28
28
|
```
|
29
29
|
%s
|
30
30
|
%s
|
31
|
+
%s
|
31
32
|
```
|
32
33
|
MESSAGE
|
33
34
|
|
@@ -81,7 +82,8 @@ module Mutant
|
|
81
82
|
|
82
83
|
puts(
|
83
84
|
EXCEPTION_ERROR_MESSAGE % [
|
84
|
-
exception.
|
85
|
+
exception.original_class,
|
86
|
+
exception.message,
|
85
87
|
exception.backtrace.join("\n")
|
86
88
|
]
|
87
89
|
)
|
data/lib/mutant/selector.rb
CHANGED
data/lib/mutant/subject.rb
CHANGED
@@ -21,59 +21,22 @@ module Mutant
|
|
21
21
|
class Memoized < self
|
22
22
|
include AST::Sexp
|
23
23
|
|
24
|
-
FREEZER_OPTION_VALUES = {
|
25
|
-
Adamantium::Freezer::Deep => :deep,
|
26
|
-
Adamantium::Freezer::Flat => :flat,
|
27
|
-
Adamantium::Freezer::Noop => :noop
|
28
|
-
}.freeze
|
29
|
-
|
30
|
-
private_constant(*constants(false))
|
31
|
-
|
32
24
|
# Prepare subject for mutation insertion
|
33
25
|
#
|
34
26
|
# @return [self]
|
35
27
|
def prepare
|
36
|
-
|
28
|
+
scope
|
29
|
+
.instance_variable_get(:@memoized_methods)
|
30
|
+
.delete(name)
|
31
|
+
|
37
32
|
super()
|
38
33
|
end
|
39
34
|
|
40
35
|
private
|
41
36
|
|
42
37
|
def wrap_node(mutant)
|
43
|
-
s(:begin, mutant, s(:send, nil, :memoize, s(:sym, name)
|
38
|
+
s(:begin, mutant, s(:send, nil, :memoize, s(:sym, name)))
|
44
39
|
end
|
45
|
-
|
46
|
-
# The optional AST node for adamantium memoization options
|
47
|
-
#
|
48
|
-
# @return [Array(Parser::AST::Node), nil]
|
49
|
-
def options
|
50
|
-
# rubocop:disable Style/GuardClause
|
51
|
-
if FREEZER_OPTION_VALUES.key?(freezer)
|
52
|
-
[
|
53
|
-
s(:kwargs,
|
54
|
-
s(:pair,
|
55
|
-
s(:sym, :freezer),
|
56
|
-
s(:sym, FREEZER_OPTION_VALUES.fetch(freezer))))
|
57
|
-
]
|
58
|
-
end
|
59
|
-
# rubocop:enable Style/GuardClause
|
60
|
-
end
|
61
|
-
|
62
|
-
# The freezer used for memoization
|
63
|
-
#
|
64
|
-
# @return [Object]
|
65
|
-
def freezer
|
66
|
-
memory.fetch(name).instance_variable_get(:@freezer)
|
67
|
-
end
|
68
|
-
memoize :freezer, freezer: :noop
|
69
|
-
|
70
|
-
# The memory used for memoization
|
71
|
-
#
|
72
|
-
# @return [ThreadSafe::Cache]
|
73
|
-
def memory
|
74
|
-
scope.__send__(:memoized_methods).instance_variable_get(:@memory)
|
75
|
-
end
|
76
|
-
|
77
40
|
end # Memoized
|
78
41
|
end # Instance
|
79
42
|
end # Method
|