mutant 0.2.7 → 0.2.8
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.
- data/Changelog.md +9 -1
- data/Gemfile.devtools +5 -12
- data/LICENSE +20 -0
- data/README.md +25 -24
- data/TODO +10 -2
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/site.reek +4 -2
- data/lib/mutant.rb +18 -9
- data/lib/mutant/context/scope.rb +3 -3
- data/lib/mutant/differ.rb +13 -1
- data/lib/mutant/killer.rb +1 -0
- data/lib/mutant/matcher/scope_methods.rb +16 -11
- data/lib/mutant/mutator.rb +10 -0
- data/lib/mutant/mutator/node.rb +5 -18
- data/lib/mutant/mutator/node/actual_arguments.rb +25 -0
- data/lib/mutant/mutator/node/arguments.rb +0 -155
- data/lib/mutant/mutator/node/default_arguments.rb +24 -0
- data/lib/mutant/mutator/node/formal_arguments_19.rb +40 -0
- data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +32 -0
- data/lib/mutant/mutator/node/formal_arguments_19/pattern_argument_expansion.rb +35 -0
- data/lib/mutant/mutator/node/formal_arguments_19/require_defaults.rb +37 -0
- data/lib/mutant/mutator/node/literal.rb +14 -0
- data/lib/mutant/mutator/node/literal/hash.rb +1 -7
- data/lib/mutant/mutator/node/pattern_arguments.rb +41 -0
- data/lib/mutant/mutator/node/pattern_variable.rb +23 -0
- data/lib/mutant/mutator/node/send.rb +76 -6
- data/lib/mutant/mutator/util.rb +0 -71
- data/lib/mutant/mutator/util/array.rb +70 -0
- data/lib/mutant/mutator/util/symbol.rb +39 -0
- data/mutant.gemspec +2 -2
- data/spec/shared/mutator_behavior.rb +3 -2
- data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +12 -0
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +24 -17
- metadata +15 -3
@@ -1,161 +1,6 @@
|
|
1
1
|
module Mutant
|
2
2
|
class Mutator
|
3
3
|
class Node
|
4
|
-
# Mutator for pattern arguments
|
5
|
-
class PatternVariable < self
|
6
|
-
|
7
|
-
handle(Rubinius::AST::PatternVariable)
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
# Emit mutations
|
12
|
-
#
|
13
|
-
# @return [undefined]
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
#
|
17
|
-
def dispatch
|
18
|
-
emit_attribute_mutations(:name)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
# Mutantor for default arguments
|
23
|
-
class DefaultArguments < self
|
24
|
-
handle(Rubinius::AST::DefaultArguments)
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
# Emit mutations
|
29
|
-
#
|
30
|
-
# @return [undefined]
|
31
|
-
#
|
32
|
-
# @api private
|
33
|
-
#
|
34
|
-
def dispatch
|
35
|
-
emit_attribute_mutations(:arguments) do |argument|
|
36
|
-
argument.names = argument.arguments.map(&:name)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Mutator for pattern arguments
|
42
|
-
class PatternArguments < self
|
43
|
-
|
44
|
-
handle(Rubinius::AST::PatternArguments)
|
45
|
-
|
46
|
-
private
|
47
|
-
|
48
|
-
# Emit mutations
|
49
|
-
#
|
50
|
-
# @return [undefined]
|
51
|
-
#
|
52
|
-
# @api private
|
53
|
-
#
|
54
|
-
def dispatch
|
55
|
-
Mutator.each(node.arguments.body) do |mutation|
|
56
|
-
dup = dup_node
|
57
|
-
dup.arguments.body = mutation
|
58
|
-
emit(dup)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
# Test if mutation should be skipped
|
63
|
-
#
|
64
|
-
# @return [true]
|
65
|
-
# if mutation should be skipped
|
66
|
-
#
|
67
|
-
# @return [false]
|
68
|
-
# otherwise
|
69
|
-
#
|
70
|
-
# @api private
|
71
|
-
#
|
72
|
-
def allow?(object)
|
73
|
-
object.arguments.body.size >= 2
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
# Mutator for formal arguments
|
78
|
-
class FormatlArguments19 < self
|
79
|
-
|
80
|
-
private
|
81
|
-
|
82
|
-
handle(Rubinius::AST::FormalArguments19)
|
83
|
-
|
84
|
-
# Emit mutations
|
85
|
-
#
|
86
|
-
# @return [undefined]
|
87
|
-
#
|
88
|
-
# @api private
|
89
|
-
#
|
90
|
-
def dispatch
|
91
|
-
expand_pattern_args
|
92
|
-
emit_default_mutations
|
93
|
-
emit_required_defaults_mutation
|
94
|
-
emit_attribute_mutations(:required) do |mutation|
|
95
|
-
mutation.names = mutation.optional + mutation.required
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
|
-
# Emit default mutations
|
100
|
-
#
|
101
|
-
# @return [undefined]
|
102
|
-
#
|
103
|
-
# @api private
|
104
|
-
#
|
105
|
-
def emit_default_mutations
|
106
|
-
return unless node.defaults
|
107
|
-
emit_attribute_mutations(:defaults) do |mutation|
|
108
|
-
mutation.optional = mutation.defaults.names
|
109
|
-
mutation.names = mutation.required + mutation.optional
|
110
|
-
if mutation.defaults.names.empty?
|
111
|
-
mutation.defaults = nil
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
# Emit required defaults mutations
|
117
|
-
#
|
118
|
-
# @return [undefined]
|
119
|
-
#
|
120
|
-
# @api private
|
121
|
-
#
|
122
|
-
def emit_required_defaults_mutation
|
123
|
-
return unless node.defaults
|
124
|
-
arguments = node.defaults.arguments
|
125
|
-
arguments.each_index do |index|
|
126
|
-
names = arguments.take(index+1).map(&:name)
|
127
|
-
dup = dup_node
|
128
|
-
defaults = dup.defaults
|
129
|
-
defaults.arguments = defaults.arguments.drop(names.size)
|
130
|
-
names.each { |name| dup.optional.delete(name) }
|
131
|
-
dup.required.concat(names)
|
132
|
-
if dup.optional.empty?
|
133
|
-
dup.defaults = nil
|
134
|
-
end
|
135
|
-
emit(dup)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# Emit pattern args expansions
|
140
|
-
#
|
141
|
-
# @return [undefined]
|
142
|
-
#
|
143
|
-
# @api private
|
144
|
-
#
|
145
|
-
def expand_pattern_args
|
146
|
-
node.required.each_with_index do |argument, index|
|
147
|
-
next unless argument.kind_of?(Rubinius::AST::PatternArguments)
|
148
|
-
dup = dup_node
|
149
|
-
required = dup.required
|
150
|
-
required.delete_at(index)
|
151
|
-
argument.arguments.body.reverse.each do |node|
|
152
|
-
required.insert(index, node.name)
|
153
|
-
end
|
154
|
-
dup.names |= required
|
155
|
-
emit(dup)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
end
|
159
4
|
|
160
5
|
# Mutator for arguments
|
161
6
|
class Arguments < self
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
# Mutantor for default arguments
|
5
|
+
class DefaultArguments < self
|
6
|
+
handle(Rubinius::AST::DefaultArguments)
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
# Emit mutations
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def dispatch
|
17
|
+
emit_attribute_mutations(:arguments) do |argument|
|
18
|
+
argument.names = argument.arguments.map(&:name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
|
5
|
+
# Mutator for formal arguments in 1.9 mode
|
6
|
+
class FormalArguments19 < self
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
handle(Rubinius::AST::FormalArguments19)
|
11
|
+
|
12
|
+
# Emit mutations
|
13
|
+
#
|
14
|
+
# @return [undefined]
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
def dispatch
|
19
|
+
run(DefaultMutations)
|
20
|
+
run(RequireDefaults)
|
21
|
+
run(PatternArgumentExpansion)
|
22
|
+
emit_required_mutations
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
# Emit required mutations
|
27
|
+
#
|
28
|
+
# @return [undefined]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
#
|
32
|
+
def emit_required_mutations
|
33
|
+
emit_attribute_mutations(:required) do |mutation|
|
34
|
+
mutation.names = mutation.optional + mutation.required
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
class FormalArguments19
|
5
|
+
|
6
|
+
# Mutator for default argument values
|
7
|
+
class DefaultMutations < Node
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Emit mutations
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def dispatch
|
18
|
+
return unless node.defaults
|
19
|
+
emit_attribute_mutations(:defaults) do |mutation|
|
20
|
+
mutation.optional = mutation.defaults.names
|
21
|
+
mutation.names = mutation.required + mutation.optional
|
22
|
+
if mutation.defaults.names.empty?
|
23
|
+
mutation.defaults = nil
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
class FormalArguments19
|
5
|
+
|
6
|
+
# Mutator that expands pattern arguments
|
7
|
+
class PatternArgumentExpansion < Node
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Emit mutations
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def dispatch
|
18
|
+
node.required.each_with_index do |argument, index|
|
19
|
+
next unless argument.kind_of?(Rubinius::AST::PatternArguments)
|
20
|
+
dup = dup_node
|
21
|
+
required = dup.required
|
22
|
+
required.delete_at(index)
|
23
|
+
argument.arguments.body.reverse.each do |node|
|
24
|
+
required.insert(index, node.name)
|
25
|
+
end
|
26
|
+
dup.names |= required
|
27
|
+
emit(dup)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
class FormalArguments19
|
5
|
+
|
6
|
+
# Mutator for removing defaults and transform them into required arguments
|
7
|
+
class RequireDefaults < Node
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Emit mutants
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def dispatch
|
18
|
+
return unless node.defaults
|
19
|
+
arguments = node.defaults.arguments
|
20
|
+
arguments.each_index do |index|
|
21
|
+
names = arguments.take(index+1).map(&:name)
|
22
|
+
dup = dup_node
|
23
|
+
defaults = dup.defaults
|
24
|
+
defaults.arguments = defaults.arguments.drop(names.size)
|
25
|
+
names.each { |name| dup.optional.delete(name) }
|
26
|
+
dup.required.concat(names)
|
27
|
+
if dup.optional.empty?
|
28
|
+
dup.defaults = nil
|
29
|
+
end
|
30
|
+
emit(dup)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -19,6 +19,20 @@ module Mutant
|
|
19
19
|
new(Rubinius::AST::FloatLiteral, value)
|
20
20
|
end
|
21
21
|
|
22
|
+
# Emit a new node with wrapping class for each entry in values
|
23
|
+
#
|
24
|
+
# @param [Array] values
|
25
|
+
#
|
26
|
+
# @return [undefined]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def emit_values(values)
|
31
|
+
values.each do |value|
|
32
|
+
emit_self(value)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
22
36
|
# Return AST representing NaN
|
23
37
|
#
|
24
38
|
# @return [Rubinius::Node::AST]
|
@@ -29,13 +29,7 @@ module Mutant
|
|
29
29
|
# @api private
|
30
30
|
#
|
31
31
|
def emit_body
|
32
|
-
array
|
33
|
-
dup = dup_array
|
34
|
-
Mutator.each(element).each do |mutation|
|
35
|
-
dup[index]=mutation
|
36
|
-
emit_self(dup)
|
37
|
-
end
|
38
|
-
end
|
32
|
+
emit_attribute_mutations(:array, Mutator::Util::Array::Element)
|
39
33
|
end
|
40
34
|
|
41
35
|
# Return array of values in literal
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
# Mutator for pattern arguments
|
5
|
+
class PatternArguments < self
|
6
|
+
|
7
|
+
handle(Rubinius::AST::PatternArguments)
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Emit mutations
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def dispatch
|
18
|
+
Mutator.each(node.arguments.body) do |mutation|
|
19
|
+
dup = dup_node
|
20
|
+
dup.arguments.body = mutation
|
21
|
+
emit(dup)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Test if mutation should be skipped
|
26
|
+
#
|
27
|
+
# @return [true]
|
28
|
+
# if mutation should be skipped
|
29
|
+
#
|
30
|
+
# @return [false]
|
31
|
+
# otherwise
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
def allow?(object)
|
36
|
+
object.arguments.body.size >= 2
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Mutator
|
3
|
+
class Node
|
4
|
+
# Mutator for pattern variable
|
5
|
+
class PatternVariable < self
|
6
|
+
|
7
|
+
handle(Rubinius::AST::PatternVariable)
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
# Emit mutations
|
12
|
+
#
|
13
|
+
# @return [undefined]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def dispatch
|
18
|
+
emit_attribute_mutations(:name)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -6,6 +6,24 @@ module Mutant
|
|
6
6
|
|
7
7
|
handle(Rubinius::AST::Send)
|
8
8
|
|
9
|
+
# Test if node corresponds to "self.class"
|
10
|
+
#
|
11
|
+
# @param [Rubinius::AST::Node] node
|
12
|
+
#
|
13
|
+
# @return [true]
|
14
|
+
# if node equals to self.class
|
15
|
+
#
|
16
|
+
# @return [false]
|
17
|
+
# otherwise
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def self.self_class?(node)
|
22
|
+
node.kind_of?(Rubinius::AST::Send) &&
|
23
|
+
node.name == :class &&
|
24
|
+
node.receiver.kind_of?(Rubinius::AST::Self)
|
25
|
+
end
|
26
|
+
|
9
27
|
private
|
10
28
|
|
11
29
|
# Emit mutations
|
@@ -15,11 +33,51 @@ module Mutant
|
|
15
33
|
# @api private
|
16
34
|
#
|
17
35
|
def dispatch
|
36
|
+
emit_receiver
|
18
37
|
emit_implicit_self_receiver
|
19
|
-
|
38
|
+
emit_receiver_mutations
|
39
|
+
emit_block_mutations
|
20
40
|
emit_block_absence_mutation
|
21
41
|
end
|
22
42
|
|
43
|
+
# Emit receiver
|
44
|
+
#
|
45
|
+
# @return [undefined]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
def emit_receiver
|
50
|
+
unless to_self?
|
51
|
+
emit(receiver)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Emit block mutations
|
56
|
+
#
|
57
|
+
# @return [undefined]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
#
|
61
|
+
def emit_block_mutations
|
62
|
+
if node.block
|
63
|
+
emit_attribute_mutations(:block)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Emit receiver mutations
|
68
|
+
#
|
69
|
+
# @return [undefined]
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
#
|
73
|
+
def emit_receiver_mutations
|
74
|
+
util = self.class
|
75
|
+
|
76
|
+
unless to_self? or util.self_class?(receiver)
|
77
|
+
emit_attribute_mutations(:receiver)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
23
81
|
# Emit block absence mutation
|
24
82
|
#
|
25
83
|
# @return [undefined]
|
@@ -55,14 +113,14 @@ module Mutant
|
|
55
113
|
# Check if receiver is self
|
56
114
|
#
|
57
115
|
# @return [true]
|
58
|
-
#
|
116
|
+
# if receiver is a Rubinius::AST::Self node
|
59
117
|
#
|
60
118
|
# @return [false]
|
61
119
|
# return false otherwise
|
62
120
|
#
|
63
121
|
# @api private
|
64
122
|
#
|
65
|
-
def
|
123
|
+
def to_self?
|
66
124
|
receiver.kind_of?(Rubinius::AST::Self)
|
67
125
|
end
|
68
126
|
|
@@ -92,9 +150,8 @@ module Mutant
|
|
92
150
|
# @api private
|
93
151
|
#
|
94
152
|
def emit_implicit_self_receiver
|
95
|
-
|
96
|
-
return if
|
97
|
-
return unless self?
|
153
|
+
return unless to_self?
|
154
|
+
return if self.class.self_class?(node)
|
98
155
|
mutant = dup_node
|
99
156
|
mutant.privately = true
|
100
157
|
# TODO: Fix rubinius to allow this as an attr_accessor
|
@@ -116,9 +173,22 @@ module Mutant
|
|
116
173
|
#
|
117
174
|
def dispatch
|
118
175
|
super
|
176
|
+
emit_call_remove_mutation
|
119
177
|
emit_attribute_mutations(:arguments)
|
120
178
|
end
|
121
179
|
|
180
|
+
# Emit transfomr call mutation
|
181
|
+
#
|
182
|
+
# @return [undefined]
|
183
|
+
#
|
184
|
+
# @api private
|
185
|
+
#
|
186
|
+
def emit_call_remove_mutation
|
187
|
+
array = node.arguments.array
|
188
|
+
return unless array.length == 1
|
189
|
+
emit(array.first)
|
190
|
+
end
|
191
|
+
|
122
192
|
end
|
123
193
|
end
|
124
194
|
end
|