mutant 0.2.12 → 0.2.13

Sign up to get free protection for your applications and to get access to all the features.
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