mutant 0.10.25 → 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 +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
|
#
|