mutant 0.10.25 → 0.10.26
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 +10 -9
- 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/fork.rb +4 -11
- data/lib/mutant/matcher.rb +1 -1
- data/lib/mutant/matcher/config.rb +3 -2
- data/lib/mutant/matcher/method.rb +8 -6
- data/lib/mutant/matcher/method/instance.rb +6 -2
- data/lib/mutant/matcher/methods.rb +2 -4
- data/lib/mutant/meta/example.rb +1 -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/literal/regex.rb +3 -17
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +3 -3
- 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 +2 -2
- data/lib/mutant/mutator/node/regopt.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +40 -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 +2 -2
- data/lib/mutant/reporter/cli/printer/env_progress.rb +2 -2
- 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/variable.rb +322 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/world.rb +1 -1
- metadata +8 -158
@@ -6,11 +6,11 @@ module Mutant
|
|
6
6
|
class Methods < self
|
7
7
|
include AbstractType, Concord.new(:scope)
|
8
8
|
|
9
|
-
CANDIDATE_NAMES =
|
9
|
+
CANDIDATE_NAMES = %i[
|
10
10
|
public_instance_methods
|
11
11
|
private_instance_methods
|
12
12
|
protected_instance_methods
|
13
|
-
]
|
13
|
+
].freeze
|
14
14
|
|
15
15
|
private_constant(*constants(false))
|
16
16
|
|
@@ -62,7 +62,6 @@ module Mutant
|
|
62
62
|
def candidate_scope
|
63
63
|
scope.singleton_class
|
64
64
|
end
|
65
|
-
memoize :candidate_scope, freezer: :noop
|
66
65
|
|
67
66
|
end # Singleton
|
68
67
|
|
@@ -79,7 +78,6 @@ module Mutant
|
|
79
78
|
def candidate_scope
|
80
79
|
scope.singleton_class
|
81
80
|
end
|
82
|
-
memoize :candidate_scope, freezer: :noop
|
83
81
|
end # Metaclass
|
84
82
|
|
85
83
|
# Matcher for instance methods
|
data/lib/mutant/meta/example.rb
CHANGED
data/lib/mutant/mutation.rb
CHANGED
data/lib/mutant/mutator.rb
CHANGED
@@ -6,7 +6,12 @@ module Mutant
|
|
6
6
|
|
7
7
|
REGISTRY = Registry.new
|
8
8
|
|
9
|
-
include
|
9
|
+
include(
|
10
|
+
Adamantium,
|
11
|
+
Concord.new(:input, :parent),
|
12
|
+
AbstractType,
|
13
|
+
Procto
|
14
|
+
)
|
10
15
|
|
11
16
|
# Lookup and invoke dedicated AST mutator
|
12
17
|
#
|
@@ -30,6 +35,8 @@ module Mutant
|
|
30
35
|
# @return [Set<Parser::AST::Node>]
|
31
36
|
attr_reader :output
|
32
37
|
|
38
|
+
alias_method :call, :output
|
39
|
+
|
33
40
|
private
|
34
41
|
|
35
42
|
def initialize(_input, _parent = nil)
|
@@ -28,11 +28,10 @@ module Mutant
|
|
28
28
|
emit_type(s(:str, NULL_REGEXP_SOURCE), options)
|
29
29
|
end
|
30
30
|
|
31
|
-
# NOTE: will only mutate parts of regexp body if the
|
32
|
-
# body is composed of only strings. Regular expressions
|
33
|
-
# with interpolation are skipped
|
34
31
|
def mutate_body
|
35
|
-
|
32
|
+
# NOTE: will only mutate parts of regexp body if the body is composed of only strings.
|
33
|
+
# Regular expressions with interpolation are skipped.
|
34
|
+
return unless (body_ast = AST::Regexp.expand_regexp_ast(input))
|
36
35
|
|
37
36
|
Mutator.mutate(body_ast).each do |mutation|
|
38
37
|
source = AST::Regexp.to_expression(mutation).to_s
|
@@ -40,19 +39,6 @@ module Mutant
|
|
40
39
|
end
|
41
40
|
end
|
42
41
|
|
43
|
-
def body_ast
|
44
|
-
AST::Regexp.to_ast(body_expression)
|
45
|
-
end
|
46
|
-
|
47
|
-
def body_expression
|
48
|
-
AST::Regexp.parse(body.map(&:children).join)
|
49
|
-
end
|
50
|
-
memoize :body_expression
|
51
|
-
|
52
|
-
def body
|
53
|
-
children.slice(0...-1)
|
54
|
-
end
|
55
|
-
|
56
42
|
end # Regex
|
57
43
|
end # Literal
|
58
44
|
end # Node
|
@@ -17,9 +17,9 @@ module Mutant
|
|
17
17
|
lvasgn: EMPTY_STRING
|
18
18
|
}
|
19
19
|
|
20
|
-
MAP =
|
21
|
-
|
22
|
-
|
20
|
+
MAP = map
|
21
|
+
.transform_values { |prefix| [prefix, /^#{::Regexp.escape(prefix)}/] }
|
22
|
+
.freeze
|
23
23
|
|
24
24
|
handle(*MAP.keys)
|
25
25
|
|
@@ -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
|
@@ -6,11 +6,11 @@ module Mutant
|
|
6
6
|
module Regexp
|
7
7
|
# Mutator for zero-or-more quantifier, `*`
|
8
8
|
class ZeroOrMore < Node
|
9
|
-
MAP =
|
9
|
+
MAP = {
|
10
10
|
regexp_greedy_zero_or_more: :regexp_greedy_one_or_more,
|
11
11
|
regexp_reluctant_zero_or_more: :regexp_reluctant_one_or_more,
|
12
12
|
regexp_possessive_zero_or_more: :regexp_possessive_one_or_more
|
13
|
-
|
13
|
+
}.freeze
|
14
14
|
|
15
15
|
handle(*MAP.keys)
|
16
16
|
|
@@ -13,7 +13,7 @@ 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?],
|
@@ -32,8 +32,8 @@ module Mutant
|
|
32
32
|
is_a?: %i[instance_of?],
|
33
33
|
kind_of?: %i[instance_of?],
|
34
34
|
map: %i[each],
|
35
|
-
method: %i[public_method],
|
36
35
|
match: %i[match?],
|
36
|
+
method: %i[public_method],
|
37
37
|
reverse_each: %i[each],
|
38
38
|
reverse_map: %i[map each],
|
39
39
|
reverse_merge: %i[merge],
|
@@ -43,13 +43,17 @@ module Mutant
|
|
43
43
|
to_i: %i[to_int],
|
44
44
|
to_s: %i[to_str],
|
45
45
|
values_at: %i[fetch_values]
|
46
|
-
)
|
46
|
+
}.freeze.tap { |hash| hash.values(&:freeze) }
|
47
47
|
|
48
|
-
RECEIVER_SELECTOR_REPLACEMENTS =
|
48
|
+
RECEIVER_SELECTOR_REPLACEMENTS = {
|
49
49
|
Date: {
|
50
50
|
parse: %i[jd civil strptime iso8601 rfc3339 xmlschema rfc2822 rfc822 httpdate jisx0301]
|
51
|
-
}
|
52
|
-
|
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
|
53
57
|
|
54
58
|
private
|
55
59
|
|
@@ -84,6 +88,7 @@ module Mutant
|
|
84
88
|
end
|
85
89
|
|
86
90
|
def emit_selector_specific_mutations
|
91
|
+
emit_start_end_with_mutations
|
87
92
|
emit_predicate_mutations
|
88
93
|
emit_array_mutation
|
89
94
|
emit_static_send
|
@@ -94,6 +99,35 @@ module Mutant
|
|
94
99
|
emit_lambda_mutation
|
95
100
|
end
|
96
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
|
+
|
97
131
|
def emit_predicate_mutations
|
98
132
|
return unless selector.match?(/\?\z/) && !selector.equal?(:defined?)
|
99
133
|
|
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
|
#
|
@@ -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
|
#
|