mutant 0.2.12 → 0.2.13

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 (48) hide show
  1. data/Changelog.md +4 -0
  2. data/Gemfile +1 -1
  3. data/Gemfile.devtools +39 -19
  4. data/README.md +3 -2
  5. data/TODO +3 -1
  6. data/config/flay.yml +1 -1
  7. data/config/site.reek +10 -3
  8. data/lib/mutant.rb +6 -73
  9. data/lib/mutant/constants.rb +49 -0
  10. data/lib/mutant/killer/forking.rb +6 -2
  11. data/lib/mutant/loader.rb +6 -79
  12. data/lib/mutant/matcher/scope_methods.rb +2 -2
  13. data/lib/mutant/mutation.rb +3 -2
  14. data/lib/mutant/mutation/filter/whitelist.rb +2 -0
  15. data/lib/mutant/mutator/node.rb +20 -9
  16. data/lib/mutant/mutator/node/assignment.rb +8 -1
  17. data/lib/mutant/mutator/node/block.rb +1 -0
  18. data/lib/mutant/mutator/node/default_arguments.rb +1 -0
  19. data/lib/mutant/mutator/node/formal_arguments_19.rb +1 -0
  20. data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +1 -0
  21. data/lib/mutant/mutator/node/{if_statement.rb → if.rb} +21 -6
  22. data/lib/mutant/mutator/node/iter_19.rb +1 -0
  23. data/lib/mutant/mutator/node/literal.rb +4 -3
  24. data/lib/mutant/mutator/node/literal/hash.rb +2 -1
  25. data/lib/mutant/mutator/node/literal/range.rb +2 -1
  26. data/lib/mutant/mutator/node/noop.rb +2 -0
  27. data/lib/mutant/mutator/node/receiver_case.rb +1 -19
  28. data/lib/mutant/mutator/node/send.rb +8 -136
  29. data/lib/mutant/mutator/node/send/binary_operator_method.rb +61 -0
  30. data/lib/mutant/mutator/node/send/with_arguments.rb +81 -0
  31. data/lib/mutant/mutator/node/super.rb +2 -0
  32. data/lib/mutant/mutator/node/{arguments.rb → when.rb} +4 -4
  33. data/lib/mutant/mutator/node/while.rb +2 -0
  34. data/lib/mutant/mutator/util/array.rb +2 -1
  35. data/lib/mutant/mutator/util/symbol.rb +1 -1
  36. data/lib/mutant/reporter/null.rb +1 -0
  37. data/lib/mutant/runner.rb +3 -4
  38. data/lib/mutant/singleton_methods.rb +28 -0
  39. data/lib/mutant/strategy.rb +2 -0
  40. data/lib/mutant/strategy/rspec/example_lookup.rb +4 -2
  41. data/mutant.gemspec +4 -4
  42. data/spec/shared/mutator_behavior.rb +1 -2
  43. data/spec/support/zombie.rb +35 -2
  44. data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +5 -6
  45. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +1 -1
  46. data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +61 -61
  47. metadata +12 -10
  48. data/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb +0 -42
@@ -106,7 +106,7 @@ module Mutant
106
106
  abstract_method :method_names
107
107
 
108
108
  class Singleton < self
109
- MATCHER = Mutant::Matcher::Method::Singleton
109
+ MATCHER = Matcher::Method::Singleton
110
110
 
111
111
  # Return method for name
112
112
  #
@@ -141,7 +141,7 @@ module Mutant
141
141
  end
142
142
 
143
143
  class Instance < self
144
- MATCHER = Mutant::Matcher::Method::Instance
144
+ MATCHER = Matcher::Method::Instance
145
145
 
146
146
  # Return method for name
147
147
  #
@@ -37,7 +37,7 @@ module Mutant
37
37
  # @api private
38
38
  #
39
39
  def insert
40
- Loader::Eval.run(root, subject.source_path, subject.source_line)
40
+ Loader::Eval.run(root, subject)
41
41
  self
42
42
  end
43
43
 
@@ -110,9 +110,10 @@ module Mutant
110
110
  @subject, @node = subject, node
111
111
  end
112
112
 
113
+ # Noop mutation
113
114
  class Noop < self
114
115
 
115
- # Initialihe object
116
+ # Initialize object
116
117
  #
117
118
  # @param [Subject] subject
118
119
  #
@@ -1,6 +1,8 @@
1
1
  module Mutant
2
2
  class Mutation
3
3
  class Filter
4
+
5
+ # Whiltelist filter
4
6
  class Whitelist < self
5
7
  include Adamantium::Flat, Equalizer.new(:whitelist)
6
8
 
@@ -103,7 +103,9 @@ module Mutant
103
103
  mutator.each(value) do |mutation|
104
104
  dup = dup_node
105
105
  dup.public_send(:"#{name}=", mutation)
106
- yield dup if block_given?
106
+ if block_given?
107
+ dup = yield(dup)
108
+ end
107
109
  emit(dup)
108
110
  end
109
111
  end
@@ -118,22 +120,31 @@ module Mutant
118
120
  emit(new_nil)
119
121
  end
120
122
 
123
+ # Return new Rubiinius::AST::SendWithArguments node
124
+ #
125
+ # @param [Rubnius::AST::Node] receiver
126
+ # @param [Symbol] name
127
+ # @param [Object] arguments
128
+ #
129
+ # @return [Rubinius::AST::SendWithArguments]
130
+ #
131
+ # @api private
132
+ #
133
+ def new_send_with_arguments(receiver, name, arguments)
134
+ new(Rubinius::AST::SendWithArguments, receiver, name, arguments)
135
+ end
136
+
121
137
  # Return AST representing send
122
138
  #
123
139
  # @param [Rubinius::AST::Node] receiver
124
140
  # @param [Symbol] name
125
- # @param [Rubinius::AST::Node] arguments
126
141
  #
127
- # @return [Rubnius::AST::SendWithArguments]
142
+ # @return [Rubnius::AST::Send]
128
143
  #
129
144
  # @api private
130
145
  #
131
- def new_send(receiver, name, arguments=nil)
132
- if arguments
133
- new(Rubinius::AST::SendWithArguments, receiver, name, arguments)
134
- else
135
- new(Rubinius::AST::Send, receiver, name)
136
- end
146
+ def new_send(receiver, name)
147
+ new(Rubinius::AST::Send, receiver, name)
137
148
  end
138
149
 
139
150
  # Return duplicated (unfrozen) node each call
@@ -1,10 +1,13 @@
1
1
  module Mutant
2
2
  class Mutator
3
3
  class Node
4
+
5
+ # Abstract base class for assignment mutators
4
6
  class Assignment < self
5
7
 
6
8
  private
7
9
 
10
+ # Abstract base class for variable assignments
8
11
  class Variable < self
9
12
 
10
13
  # Emit mutants
@@ -16,32 +19,36 @@ module Mutant
16
19
  def dispatch
17
20
  emit_attribute_mutations(:name) do |mutation|
18
21
  mutation.name = "#{self.class::PREFIX}#{mutation.name}".to_sym
22
+ mutation
19
23
  end
20
24
  emit_attribute_mutations(:value)
21
25
  end
22
26
 
27
+ # Mutator for local variable assignments
23
28
  class Local < self
24
29
  PREFIX = ''.freeze
25
30
  handle(Rubinius::AST::LocalVariableAssignment)
26
31
  end
27
32
 
33
+ # Mutator for instance variable assignments
28
34
  class Instance < self
29
35
  PREFIX = '@'.freeze
30
36
  handle(Rubinius::AST::InstanceVariableAssignment)
31
37
  end
32
38
 
39
+ # Mutator for class variable assignments
33
40
  class Class < self
34
41
  PREFIX = '@@'.freeze
35
42
  handle(Rubinius::AST::ClassVariableAssignment)
36
43
  end
37
44
 
45
+ # Mutator for global variable assignments
38
46
  class Global < self
39
47
  PREFIX = '$'.freeze
40
48
  handle(Rubinius::AST::GlobalVariableAssignment)
41
49
  end
42
50
 
43
51
  end
44
-
45
52
  end
46
53
  end
47
54
  end
@@ -22,6 +22,7 @@ module Mutant
22
22
  if array.empty?
23
23
  array << new_nil
24
24
  end
25
+ mutation
25
26
  end
26
27
  end
27
28
 
@@ -16,6 +16,7 @@ module Mutant
16
16
  def dispatch
17
17
  emit_attribute_mutations(:arguments) do |argument|
18
18
  argument.names = argument.arguments.map(&:name)
19
+ argument
19
20
  end
20
21
  end
21
22
  end
@@ -32,6 +32,7 @@ module Mutant
32
32
  def emit_required_mutations
33
33
  emit_attribute_mutations(:required) do |mutation|
34
34
  mutation.names = mutation.optional + mutation.required
35
+ mutation
35
36
  end
36
37
  end
37
38
  end
@@ -22,6 +22,7 @@ module Mutant
22
22
  if mutation.defaults.names.empty?
23
23
  mutation.defaults = nil
24
24
  end
25
+ mutation
25
26
  end
26
27
  end
27
28
 
@@ -2,7 +2,7 @@ module Mutant
2
2
  class Mutator
3
3
  class Node
4
4
  # Mutator for Rubinius::AST::If nodes
5
- class IfStatement < self
5
+ class If < self
6
6
 
7
7
  handle(Rubinius::AST::If)
8
8
 
@@ -16,13 +16,29 @@ module Mutant
16
16
  #
17
17
  def dispatch
18
18
  emit_attribute_mutations(:condition)
19
- emit_attribute_mutations(:body) if node.body.class != Rubinius::AST::NilLiteral
20
- emit_attribute_mutations(:else) if node.else.class != Rubinius::AST::NilLiteral
19
+ emit_attribute_mutations(:body) unless nil_literal?(:body)
20
+ emit_attribute_mutations(:else) unless nil_literal?(:else)
21
21
  emit_inverted_condition
22
22
  emit_deleted_if_branch
23
23
  emit_deleted_else_branch
24
24
  end
25
25
 
26
+ # Test if attribute is non nil literal
27
+ #
28
+ # @param [Symbol] name
29
+ #
30
+ # @return [true]
31
+ # if attribute value a nil literal
32
+ #
33
+ # @return [false]
34
+ # otherwise
35
+ #
36
+ # @api private
37
+ #
38
+ def nil_literal?(name)
39
+ node.public_send(name).kind_of?(Rubinius::AST::NilLiteral)
40
+ end
41
+
26
42
  # Emit inverted condition
27
43
  #
28
44
  # Especially the same like swap branches but more universal as it also
@@ -53,9 +69,8 @@ module Mutant
53
69
  # @api private
54
70
  #
55
71
  def emit_deleted_if_branch
56
- body = else_branch
57
- return unless body
58
- emit_self(condition, else_branch, nil)
72
+ body = else_branch || return
73
+ emit_self(condition, body, nil)
59
74
  end
60
75
 
61
76
  # Return if_branch of node
@@ -17,6 +17,7 @@ module Mutant
17
17
  emit_attribute_mutations(:arguments) do |mutation|
18
18
  arguments = mutation.arguments
19
19
  arguments.names = arguments.required + arguments.optional
20
+ mutation
20
21
  end if node.arguments
21
22
  end
22
23
 
@@ -40,7 +40,8 @@ module Mutant
40
40
  # @api private
41
41
  #
42
42
  def nan
43
- new_send(new_float(0), :/, new_float(0))
43
+ zero_float = new_float(0)
44
+ new_send_with_arguments(zero_float, :/, zero_float)
44
45
  end
45
46
 
46
47
  # Return AST representing negative infinity
@@ -50,7 +51,7 @@ module Mutant
50
51
  # @api private
51
52
  #
52
53
  def negative_infinity
53
- new(Rubinius::AST::Negate, infinity)
54
+ new_send_with_arguments(new_float(-1), :/, new_float(0))
54
55
  end
55
56
 
56
57
  # Return AST representing infinity
@@ -60,7 +61,7 @@ module Mutant
60
61
  # @api private
61
62
  #
62
63
  def infinity
63
- new_send(new_float(1), :/, new_float(0))
64
+ new_send_with_arguments(new_float(1), :/, new_float(0))
64
65
  end
65
66
  end
66
67
  end
@@ -59,7 +59,8 @@ module Mutant
59
59
  # @api private
60
60
  #
61
61
  def values
62
- [[], [new_nil, new_nil] + dup_array]
62
+ nil_node = new_nil
63
+ [[], [nil_node, nil_node] + dup_array]
63
64
  end
64
65
 
65
66
  # Emit element presence mutations
@@ -27,7 +27,8 @@ module Mutant
27
27
  # @api private
28
28
  #
29
29
  def inverse
30
- new(inverse_class,node.start, node.finish)
30
+ node = self.node
31
+ new(inverse_class, node.start, node.finish)
31
32
  end
32
33
 
33
34
  # Emit range specific mutants
@@ -35,6 +35,8 @@ module Mutant
35
35
  handle(Rubinius::AST::OpAssignOr19)
36
36
  handle(Rubinius::AST::BlockPass19)
37
37
  handle(Rubinius::AST::OpAssign1)
38
+ handle(Rubinius::AST::OpAssign2)
39
+ handle(Rubinius::AST::SplatValue)
38
40
  handle(Rubinius::AST::ConstantAccess)
39
41
  handle(Rubinius::AST::Yield)
40
42
  handle(Rubinius::AST::Begin)
@@ -1,24 +1,6 @@
1
1
  module Mutant
2
2
  class Mutator
3
3
  class Node
4
- # Mutator for Rubinius::AST::When nodes
5
- class When < self
6
-
7
- handle(Rubinius::AST::When)
8
-
9
- private
10
-
11
- # Emit mutations
12
- #
13
- # @return [undefined]
14
- #
15
- # @api private
16
- #
17
- def dispatch
18
- emit_attribute_mutations(:body)
19
- end
20
-
21
- end
22
4
 
23
5
  # Mutator for Rubinius::AST::ReceiverCase nodes
24
6
  class ReceiverCase < self
@@ -57,7 +39,7 @@ module Mutant
57
39
  # @api private
58
40
  #
59
41
  def emit_when_branch_mutations
60
- when_branches.each_with_index do |branch,index|
42
+ when_branches.each_with_index do |branch, index|
61
43
  Mutator.each(branch) do |mutant|
62
44
  branches = dup_when_branches
63
45
  branches[index]=mutant
@@ -1,29 +1,12 @@
1
1
  module Mutant
2
2
  class Mutator
3
3
  class Node
4
- # Class for mutations where messages are send to objects
4
+
5
+ # Namespace for send mutators
5
6
  class Send < self
6
7
 
7
8
  handle(Rubinius::AST::Send)
8
9
 
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.keyword_name?(node)
22
- node.kind_of?(Rubinius::AST::Send) &&
23
- Mutant::KEYWORDS.include?(node.name) &&
24
- node.receiver.kind_of?(Rubinius::AST::Self)
25
- end
26
-
27
10
  private
28
11
 
29
12
  # Emit mutations
@@ -59,9 +42,7 @@ module Mutant
59
42
  # @api private
60
43
  #
61
44
  def emit_block_mutations
62
- if node.block
63
- emit_attribute_mutations(:block)
64
- end
45
+ emit_attribute_mutations(:block) if node.block
65
46
  end
66
47
 
67
48
  # Emit receiver mutations
@@ -71,11 +52,7 @@ module Mutant
71
52
  # @api private
72
53
  #
73
54
  def emit_receiver_mutations
74
- util = self.class
75
-
76
- unless to_self? or util.keyword_name?(receiver)
77
- emit_attribute_mutations(:receiver)
78
- end
55
+ emit_attribute_mutations(:receiver)
79
56
  end
80
57
 
81
58
  # Emit block absence mutation
@@ -150,119 +127,14 @@ module Mutant
150
127
  # @api private
151
128
  #
152
129
  def emit_implicit_self_receiver
153
- return unless to_self?
154
- return if self.class.keyword_name?(node)
130
+ unless to_self? and !Mutant::KEYWORDS.include?(node.name)
131
+ return
132
+ end
133
+
155
134
  mutant = dup_node
156
135
  mutant.privately = true
157
- # TODO: Fix rubinius to allow this as an attr_accessor
158
- mutant.instance_variable_set(:@vcall_style, true)
159
136
  emit(mutant)
160
137
  end
161
-
162
- class SendWithArguments < self
163
-
164
- handle(Rubinius::AST::SendWithArguments)
165
-
166
- class BinaryOperatorMethod < Node
167
-
168
- private
169
-
170
- # Emit mutations
171
- #
172
- # @return [undefined]
173
- #
174
- # @api private
175
- #
176
- def dispatch
177
- emit_left_mutations
178
- emit_right_mutations
179
- end
180
-
181
- # Emit left mutations
182
- #
183
- # @return [undefined]
184
- #
185
- # @api private
186
- #
187
- def emit_left_mutations
188
- emit_attribute_mutations(:receiver)
189
- end
190
-
191
- # Emit right mutations
192
- #
193
- # @return [undefined]
194
- #
195
- # @api private
196
- #
197
- def emit_right_mutations
198
- right = node.arguments.array.first
199
- Mutator.each(right).each do |mutated|
200
- dup = dup_node
201
- dup.arguments.array[0] = mutated
202
- emit(dup)
203
- end
204
- end
205
-
206
- end
207
-
208
- private
209
-
210
- # Emit mutations
211
- #
212
- # @return [undefined]
213
- #
214
- # @api private
215
- #
216
- def dispatch
217
- super
218
- emit_call_remove_mutation
219
- emit_argument_mutations
220
- end
221
-
222
- # Test if message is a binary operator
223
- #
224
- # @return [true]
225
- # if message is a binary operator
226
- #
227
- # @return [false]
228
- # otherwise
229
- #
230
- # @api private
231
- #
232
- def binary_operator?
233
- Mutant::BINARY_METHOD_OPERATORS.include?(node.name)
234
- end
235
-
236
- # Emit argument mutations
237
- #
238
- # @api private
239
- #
240
- # @return [undefined]
241
- #
242
- # @api private
243
- #
244
- def emit_argument_mutations
245
- if binary_operator?
246
- run(BinaryOperatorMethod)
247
- return
248
- end
249
-
250
- emit_attribute_mutations(:arguments)
251
- end
252
-
253
- # Emit transfomr call mutation
254
- #
255
- # @return [undefined]
256
- #
257
- # @api private
258
- #
259
- def emit_call_remove_mutation
260
- array = node.arguments.array
261
- return unless array.length == 1
262
- emit(array.first)
263
- end
264
-
265
- end
266
138
  end
267
139
  end
268
140
  end