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.
Files changed (35) hide show
  1. data/Changelog.md +9 -1
  2. data/Gemfile.devtools +5 -12
  3. data/LICENSE +20 -0
  4. data/README.md +25 -24
  5. data/TODO +10 -2
  6. data/config/flay.yml +2 -2
  7. data/config/flog.yml +1 -1
  8. data/config/site.reek +4 -2
  9. data/lib/mutant.rb +18 -9
  10. data/lib/mutant/context/scope.rb +3 -3
  11. data/lib/mutant/differ.rb +13 -1
  12. data/lib/mutant/killer.rb +1 -0
  13. data/lib/mutant/matcher/scope_methods.rb +16 -11
  14. data/lib/mutant/mutator.rb +10 -0
  15. data/lib/mutant/mutator/node.rb +5 -18
  16. data/lib/mutant/mutator/node/actual_arguments.rb +25 -0
  17. data/lib/mutant/mutator/node/arguments.rb +0 -155
  18. data/lib/mutant/mutator/node/default_arguments.rb +24 -0
  19. data/lib/mutant/mutator/node/formal_arguments_19.rb +40 -0
  20. data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +32 -0
  21. data/lib/mutant/mutator/node/formal_arguments_19/pattern_argument_expansion.rb +35 -0
  22. data/lib/mutant/mutator/node/formal_arguments_19/require_defaults.rb +37 -0
  23. data/lib/mutant/mutator/node/literal.rb +14 -0
  24. data/lib/mutant/mutator/node/literal/hash.rb +1 -7
  25. data/lib/mutant/mutator/node/pattern_arguments.rb +41 -0
  26. data/lib/mutant/mutator/node/pattern_variable.rb +23 -0
  27. data/lib/mutant/mutator/node/send.rb +76 -6
  28. data/lib/mutant/mutator/util.rb +0 -71
  29. data/lib/mutant/mutator/util/array.rb +70 -0
  30. data/lib/mutant/mutator/util/symbol.rb +39 -0
  31. data/mutant.gemspec +2 -2
  32. data/spec/shared/mutator_behavior.rb +3 -2
  33. data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +12 -0
  34. data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +24 -17
  35. 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.each_with_index do |element, index|
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
- emit_attribute_mutations(:block) if node.block
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
- # returns true when receiver is a Rubinius::AST::Self node
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 self?
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
- # FIXME: Edge case that is currently not very well undestood
96
- return if name == :block_given?
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