mutant 0.2.20 → 0.3.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +10 -11
  3. data/Changelog.md +93 -38
  4. data/Gemfile +3 -1
  5. data/Gemfile.devtools +16 -20
  6. data/Guardfile +1 -1
  7. data/README.md +36 -16
  8. data/Rakefile +21 -2
  9. data/TODO +11 -7
  10. data/bin/mutant +4 -0
  11. data/bin/zombie +4 -0
  12. data/config/devtools.yml +2 -0
  13. data/config/flay.yml +2 -2
  14. data/config/flog.yml +1 -1
  15. data/config/{site.reek → reek.yml} +94 -70
  16. data/lib/mutant/cli/classifier/method.rb +100 -0
  17. data/lib/mutant/cli/classifier/namespace.rb +47 -0
  18. data/lib/mutant/cli/classifier/scope.rb +35 -0
  19. data/lib/mutant/cli/classifier.rb +141 -0
  20. data/lib/mutant/cli.rb +115 -162
  21. data/lib/mutant/color.rb +2 -2
  22. data/lib/mutant/config.rb +27 -0
  23. data/lib/mutant/constants.rb +32 -17
  24. data/lib/mutant/context/scope.rb +33 -51
  25. data/lib/mutant/context.rb +8 -19
  26. data/lib/mutant/differ.rb +5 -5
  27. data/lib/mutant/helper.rb +2 -17
  28. data/lib/mutant/killer/forked.rb +44 -0
  29. data/lib/mutant/killer/forking.rb +3 -57
  30. data/lib/mutant/killer/rspec.rb +16 -20
  31. data/lib/mutant/killer/static.rb +6 -7
  32. data/lib/mutant/killer.rb +48 -74
  33. data/lib/mutant/loader.rb +6 -6
  34. data/lib/mutant/matcher/chain.rb +4 -25
  35. data/lib/mutant/matcher/method/instance.rb +14 -24
  36. data/lib/mutant/matcher/method/singleton.rb +35 -46
  37. data/lib/mutant/matcher/method.rb +95 -83
  38. data/lib/mutant/matcher/{scope_methods.rb → methods.rb} +53 -76
  39. data/lib/mutant/matcher/namespace.rb +71 -0
  40. data/lib/mutant/matcher/scope.rb +34 -0
  41. data/lib/mutant/matcher.rb +24 -34
  42. data/lib/mutant/mutation/evil.rb +35 -0
  43. data/lib/mutant/mutation/filter/code.rb +7 -28
  44. data/lib/mutant/mutation/filter/regexp.rb +6 -18
  45. data/lib/mutant/mutation/filter/whitelist.rb +5 -4
  46. data/lib/mutant/mutation/filter.rb +10 -9
  47. data/lib/mutant/mutation/neutral.rb +35 -0
  48. data/lib/mutant/mutation.rb +21 -61
  49. data/lib/mutant/mutator/node/argument.rb +88 -0
  50. data/lib/mutant/mutator/node/arguments.rb +52 -0
  51. data/lib/mutant/mutator/node/assignment.rb +34 -38
  52. data/lib/mutant/mutator/node/begin.rb +33 -0
  53. data/lib/mutant/mutator/node/block.rb +14 -14
  54. data/lib/mutant/mutator/node/case.rb +59 -0
  55. data/lib/mutant/mutator/node/define.rb +26 -22
  56. data/lib/mutant/mutator/node/if.rb +31 -71
  57. data/lib/mutant/mutator/node/literal/array.rb +25 -9
  58. data/lib/mutant/mutator/node/literal/boolean.rb +13 -30
  59. data/lib/mutant/mutator/node/literal/dynamic.rb +6 -5
  60. data/lib/mutant/mutator/node/literal/fixnum.rb +18 -7
  61. data/lib/mutant/mutator/node/literal/float.rb +15 -8
  62. data/lib/mutant/mutator/node/literal/hash.rb +33 -52
  63. data/lib/mutant/mutator/node/literal/nil.rb +8 -7
  64. data/lib/mutant/mutator/node/literal/range.rb +25 -50
  65. data/lib/mutant/mutator/node/literal/regex.rb +15 -23
  66. data/lib/mutant/mutator/node/literal/string.rb +7 -6
  67. data/lib/mutant/mutator/node/literal/symbol.rb +7 -6
  68. data/lib/mutant/mutator/node/literal.rb +4 -46
  69. data/lib/mutant/mutator/node/mlhs.rb +27 -0
  70. data/lib/mutant/mutator/node/noop.rb +18 -43
  71. data/lib/mutant/mutator/node/return.rb +8 -8
  72. data/lib/mutant/mutator/node/send/binary.rb +31 -0
  73. data/lib/mutant/mutator/node/send.rb +106 -72
  74. data/lib/mutant/mutator/node/super.rb +15 -20
  75. data/lib/mutant/mutator/node/when.rb +32 -7
  76. data/lib/mutant/mutator/node/while.rb +9 -7
  77. data/lib/mutant/mutator/node.rb +116 -66
  78. data/lib/mutant/mutator/registry.rb +14 -11
  79. data/lib/mutant/mutator/util/array.rb +9 -9
  80. data/lib/mutant/mutator/util/symbol.rb +6 -20
  81. data/lib/mutant/mutator/util.rb +6 -3
  82. data/lib/mutant/mutator.rb +12 -28
  83. data/lib/mutant/node_helpers.rb +28 -0
  84. data/lib/mutant/random.rb +3 -2
  85. data/lib/mutant/reporter/cli/printer/config.rb +174 -0
  86. data/lib/mutant/reporter/cli/printer/killer.rb +42 -0
  87. data/lib/mutant/reporter/cli/printer/mutation.rb +55 -0
  88. data/lib/mutant/reporter/cli/printer/subject.rb +147 -0
  89. data/lib/mutant/reporter/cli/printer.rb +165 -0
  90. data/lib/mutant/reporter/cli.rb +9 -277
  91. data/lib/mutant/reporter/null.rb +6 -30
  92. data/lib/mutant/reporter.rb +6 -73
  93. data/lib/mutant/runner/config.rb +82 -0
  94. data/lib/mutant/runner/mutation.rb +58 -0
  95. data/lib/mutant/runner/subject.rb +81 -0
  96. data/lib/mutant/runner.rb +42 -92
  97. data/lib/mutant/singleton_methods.rb +2 -2
  98. data/lib/mutant/strategy/method_expansion.rb +51 -0
  99. data/lib/mutant/strategy/rspec/dm2/lookup/method.rb +142 -0
  100. data/lib/mutant/strategy/rspec/dm2/lookup.rb +61 -0
  101. data/lib/mutant/strategy/rspec/dm2.rb +22 -0
  102. data/lib/mutant/strategy/rspec.rb +20 -22
  103. data/lib/mutant/strategy/static.rb +18 -0
  104. data/lib/mutant/strategy.rb +15 -50
  105. data/lib/mutant/subject/method.rb +100 -0
  106. data/lib/mutant/subject.rb +18 -49
  107. data/lib/mutant/support/method_object.rb +4 -2
  108. data/lib/mutant.rb +40 -35
  109. data/mutant.gemspec +9 -8
  110. data/spec/integration/mutant/rspec_killer_spec.rb +3 -3
  111. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +9 -0
  112. data/spec/integration/mutant/zombie_spec.rb +1 -1
  113. data/spec/shared/method_matcher_behavior.rb +35 -0
  114. data/spec/shared/mutator_behavior.rb +63 -32
  115. data/spec/spec_helper.rb +13 -3
  116. data/spec/support/ice_nine_config.rb +8 -0
  117. data/spec/support/rspec.rb +1 -1
  118. data/spec/support/zombie.rb +1 -1
  119. data/spec/unit/mutant/cli/class_methods/new_spec.rb +42 -28
  120. data/spec/unit/mutant/cli/class_methods/run_spec.rb +15 -13
  121. data/spec/unit/mutant/cli/classifier/class_methods/build_spec.rb +44 -0
  122. data/spec/unit/mutant/context/scope/root_spec.rb +4 -4
  123. data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +6 -5
  124. data/spec/unit/mutant/killer/success_predicate_spec.rb +28 -0
  125. data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +1 -1
  126. data/spec/unit/mutant/matcher/chain/each_spec.rb +1 -1
  127. data/spec/unit/mutant/matcher/chain/matchers_spec.rb +1 -1
  128. data/spec/unit/mutant/matcher/method/instance/each_spec.rb +112 -0
  129. data/spec/unit/mutant/matcher/method/singleton/each_spec.rb +93 -0
  130. data/spec/unit/mutant/matcher/methods/instance/each_spec.rb +59 -0
  131. data/spec/unit/mutant/matcher/methods/singleton/each_spec.rb +53 -0
  132. data/spec/unit/mutant/matcher/namespace/each_spec.rb +37 -0
  133. data/spec/unit/mutant/mutator/node/begin/mutation_spec.rb +33 -0
  134. data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +42 -14
  135. data/spec/unit/mutant/mutator/node/case/mutation_spec.rb +319 -0
  136. data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +31 -27
  137. data/spec/unit/mutant/mutator/node/if/mutation_spec.rb +75 -0
  138. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -1
  139. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +2 -2
  140. data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +1 -3
  141. data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +1 -9
  142. data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +6 -2
  143. data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +111 -108
  144. data/spec/unit/mutant/mutator/node/super/mutation_spec.rb +0 -33
  145. data/spec/unit/mutant/mutator/node/while/mutation_spec.rb +2 -2
  146. data/spec/unit/mutant/runner/config/subjects_spec.rb +38 -0
  147. data/spec/unit/mutant/runner/config/success_predicate_spec.rb +53 -0
  148. data/spec/unit/mutant/runner/failed_predicte_spec.rb +33 -0
  149. data/spec/unit/mutant/runner/mutation/killer_spec.rb +39 -0
  150. data/spec/unit/mutant/runner/subject/success_predicate_spec.rb +49 -0
  151. data/spec/unit/mutant/strategy/method_expansion/class_methods/run_spec.rb +49 -0
  152. data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/instance/spec_files_spec.rb +52 -0
  153. data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/singleton/spec_files_spec.rb +42 -0
  154. data/spec/unit/mutant/subject/context_spec.rb +6 -3
  155. data/spec/unit/mutant/subject/each_spec.rb +11 -8
  156. data/spec/unit/mutant/subject/node_spec.rb +6 -2
  157. data/test_app/spec/shared/method_filter_parse_behavior.rb +0 -2
  158. data/test_app/spec/shared/method_match_behavior.rb +1 -1
  159. data/test_app/spec/spec_helper.rb +4 -2
  160. metadata +101 -109
  161. data/config/roodi.yml +0 -26
  162. data/lib/mutant/matcher/method/classifier.rb +0 -141
  163. data/lib/mutant/matcher/object_space.rb +0 -114
  164. data/lib/mutant/mutator/node/actual_arguments.rb +0 -25
  165. data/lib/mutant/mutator/node/default_arguments.rb +0 -25
  166. data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +0 -33
  167. data/lib/mutant/mutator/node/formal_arguments_19/pattern_argument_expansion.rb +0 -35
  168. data/lib/mutant/mutator/node/formal_arguments_19/require_defaults.rb +0 -37
  169. data/lib/mutant/mutator/node/formal_arguments_19.rb +0 -41
  170. data/lib/mutant/mutator/node/iter_19.rb +0 -27
  171. data/lib/mutant/mutator/node/literal/empty_array.rb +0 -26
  172. data/lib/mutant/mutator/node/pattern_arguments.rb +0 -41
  173. data/lib/mutant/mutator/node/pattern_variable.rb +0 -23
  174. data/lib/mutant/mutator/node/receiver_case.rb +0 -122
  175. data/lib/mutant/mutator/node/send/binary_operator_method.rb +0 -61
  176. data/lib/mutant/mutator/node/send/with_arguments.rb +0 -81
  177. data/lib/mutant/reporter/stats.rb +0 -120
  178. data/lib/mutant/strategy/rspec/example_lookup.rb +0 -163
  179. data/spec/integration/mutant/method_matching_spec.rb +0 -269
  180. data/spec/shared/method_match_behavior.rb +0 -39
  181. data/spec/unit/mutant/killer/fail_ques_spec.rb +0 -39
  182. data/spec/unit/mutant/matcher/class_methods/from_string_spec.rb +0 -49
  183. data/spec/unit/mutant/matcher/class_methods/parse_spec.rb +0 -12
  184. data/spec/unit/mutant/matcher/method/class_methods/parse_spec.rb +0 -21
  185. data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +0 -52
  186. data/spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb +0 -24
  187. data/spec/unit/mutant/matcher/object_space/each_spec.rb +0 -31
  188. data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +0 -60
  189. data/spec/unit/mutant/mutator/node/receiver_case/mutation_spec.rb +0 -27
  190. data/spec/unit/mutant/strategy/rspec/example_lookup/spec_file_spec.rb +0 -236
  191. data/spec/unit/mutant/subject/class_methods/new_spec.rb +0 -13
  192. data/tasks/metrics/ci.rake +0 -7
  193. data/tasks/metrics/flay.rake +0 -41
  194. data/tasks/metrics/flog.rake +0 -43
  195. data/tasks/metrics/heckle.rake +0 -216
  196. data/tasks/metrics/metric_fu.rake +0 -31
  197. data/tasks/metrics/reek.rake +0 -15
  198. data/tasks/metrics/roodi.rake +0 -15
  199. data/tasks/metrics/yardstick.rake +0 -23
  200. data/tasks/spec.rake +0 -45
  201. data/tasks/yard.rake +0 -9
@@ -2,10 +2,20 @@ module Mutant
2
2
  class Mutator
3
3
  class Node
4
4
  class Literal
5
+
5
6
  # Abstract literal range mutator
6
7
  class Range < self
7
8
  include AbstractType
8
9
 
10
+ MAP = {
11
+ :irange => :erange,
12
+ :erange => :irange
13
+ }.freeze
14
+
15
+ children :start, :_end
16
+
17
+ handle(*MAP.keys)
18
+
9
19
  private
10
20
 
11
21
  # Emit mutants
@@ -16,30 +26,19 @@ module Mutant
16
26
  #
17
27
  def dispatch
18
28
  emit_nil
19
- emit(inverse)
20
- emit_range
29
+ emit_inverse
30
+ emit_start_mutations
31
+ emit_end_mutations
21
32
  end
22
33
 
23
34
  # Return inverse node
24
35
  #
25
- # @return [Rubinius::AST::Node]
36
+ # @return [Parser::AST::Node]
26
37
  #
27
38
  # @api private
28
39
  #
29
- def inverse
30
- node = self.node
31
- new(inverse_class, node.start, node.finish)
32
- end
33
-
34
- # Emit range specific mutants
35
- #
36
- # @return [undefined]
37
- #
38
- # @api private
39
- #
40
- def emit_range
41
- emit_finish_mutations
42
- emit_start_mutations
40
+ def emit_inverse
41
+ emit(s(MAP.fetch(node.type), *children))
43
42
  end
44
43
 
45
44
  # Emit range start mutations
@@ -48,10 +47,9 @@ module Mutant
48
47
  #
49
48
  # @api private
50
49
  #
51
- def emit_finish_mutations
52
- finish = node.finish
50
+ def emit_end_mutations
53
51
  #emit_self(negative_infinity, finish)
54
- emit_self(nan, finish)
52
+ emit_self(NAN, _end)
55
53
  end
56
54
 
57
55
  # Emit start mutations
@@ -61,35 +59,12 @@ module Mutant
61
59
  # @api private
62
60
  #
63
61
  def emit_start_mutations
64
- start = node.start
65
- emit_self(start, infinity)
66
- emit_self(start, nan)
62
+ emit_self(start, INFINITY)
63
+ emit_self(start, NAN)
67
64
  end
68
65
 
69
- # Return inverse AST node class
70
- #
71
- # @return [Class:Rubinius::AST::Node]
72
- #
73
- # @api private
74
- #
75
- def inverse_class
76
- self.class::INVERSE_CLASS
77
- end
78
-
79
- # Mutator for range exclude literals
80
- class Exclude < self
81
- INVERSE_CLASS = Rubinius::AST::Range
82
- handle(Rubinius::AST::RangeExclude)
83
-
84
- end
85
-
86
- # Mutator for range include literals
87
- class Include < self
88
- INVERSE_CLASS = Rubinius::AST::RangeExclude
89
- handle(Rubinius::AST::Range)
90
- end
91
- end
92
- end
93
- end
94
- end
95
- end
66
+ end # Range
67
+ end # Literal
68
+ end # Node
69
+ end # Mutator
70
+ end # Mutant
@@ -5,7 +5,14 @@ module Mutant
5
5
  # Mutator for regexp literals
6
6
  class Regex < self
7
7
 
8
- handle(Rubinius::AST::RegexLiteral)
8
+ handle(:regexp)
9
+
10
+ EMPTY_STRING = ''.freeze
11
+
12
+ # No input can ever be matched with this
13
+ NULL_REGEXP_SOURCE = 'a\A'.freeze
14
+
15
+ children :source, :options
9
16
 
10
17
  private
11
18
 
@@ -17,27 +24,12 @@ module Mutant
17
24
  #
18
25
  def dispatch
19
26
  emit_nil
20
- emit_self('') # match all
21
- emit_self('a\A') # match nothing
22
- emit_new { new_self(Random.hex_string) }
27
+ emit_self(s(:str, EMPTY_STRING), options)
28
+ emit_self(s(:str, NULL_REGEXP_SOURCE), options)
23
29
  end
24
30
 
25
- # Return new Rubinius::AST::Regex
26
- #
27
- # @param [String] source
28
- #
29
- # @param [Integer] options
30
- # options of regexp, defaults to mutation subject node options
31
- #
32
- # @return [undefined]
33
- #
34
- # @api private
35
- #
36
- def new_self(source,options=nil)
37
- super(source,options || node.options)
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
31
+ end # Regex
32
+ end # Literal
33
+ end # Node
34
+ end # Mutator
35
+ end # Mutant
@@ -5,7 +5,7 @@ module Mutant
5
5
  # Mutator for string literals
6
6
  class String < self
7
7
 
8
- handle(Rubinius::AST::StringLiteral)
8
+ handle(:str)
9
9
 
10
10
  private
11
11
 
@@ -19,8 +19,9 @@ module Mutant
19
19
  emit_nil
20
20
  emit_new { new_self(Random.hex_string) }
21
21
  end
22
- end
23
- end
24
- end
25
- end
26
- end
22
+
23
+ end # String
24
+ end # Literal
25
+ end # Node
26
+ end # Mutator
27
+ end # Mutant
@@ -5,7 +5,7 @@ module Mutant
5
5
  # Mutator for symbol literals
6
6
  class Symbol < self
7
7
 
8
- handle(Rubinius::AST::SymbolLiteral)
8
+ handle(:sym)
9
9
 
10
10
  private
11
11
 
@@ -19,8 +19,9 @@ module Mutant
19
19
  emit_nil
20
20
  emit_new { new_self(('s'+Random.hex_string).to_sym) }
21
21
  end
22
- end
23
- end
24
- end
25
- end
26
- end
22
+
23
+ end # Symbol
24
+ end # Literal
25
+ end # Node
26
+ end # Mutator
27
+ end # Mutant
@@ -7,18 +7,6 @@ module Mutant
7
7
 
8
8
  private
9
9
 
10
- # Return new float literal
11
- #
12
- # @param [#to_f] value
13
- #
14
- # @return [Rubinius::Node::FloatLiteral]
15
- #
16
- # @api private
17
- #
18
- def new_float(value)
19
- new(Rubinius::AST::FloatLiteral, value)
20
- end
21
-
22
10
  # Emit a new node with wrapping class for each entry in values
23
11
  #
24
12
  # @param [Array] values
@@ -33,37 +21,7 @@ module Mutant
33
21
  end
34
22
  end
35
23
 
36
- # Return AST representing NaN
37
- #
38
- # @return [Rubinius::Node::AST]
39
- #
40
- # @api private
41
- #
42
- def nan
43
- zero_float = new_float(0)
44
- new_send_with_arguments(zero_float, :/, zero_float)
45
- end
46
-
47
- # Return AST representing negative infinity
48
- #
49
- # @return [Rubinius::Node::AST]
50
- #
51
- # @api private
52
- #
53
- def negative_infinity
54
- new_send_with_arguments(new_float(-1), :/, new_float(0))
55
- end
56
-
57
- # Return AST representing infinity
58
- #
59
- # @return [Rubinius::Node::AST]
60
- #
61
- # @api private
62
- #
63
- def infinity
64
- new_send_with_arguments(new_float(1), :/, new_float(0))
65
- end
66
- end
67
- end
68
- end
69
- end
24
+ end # Literal
25
+ end # Node
26
+ end # Mutator
27
+ end # Mutant
@@ -0,0 +1,27 @@
1
+ module Mutant
2
+ class Mutator
3
+ class Node
4
+ # Mutator for multiple assignment left hand side nodes
5
+ class MLHS < self
6
+
7
+ handle(:mlhs)
8
+
9
+ private
10
+
11
+ # Emit mutations
12
+ #
13
+ # @return [undefined]
14
+ #
15
+ # @api private
16
+ #
17
+ def dispatch
18
+ children.each_index do |index|
19
+ mutate_child(index)
20
+ delete_child(index)
21
+ end
22
+ end
23
+
24
+ end # MLHS
25
+ end # Node
26
+ end # Mutator
27
+ end # Mutant
@@ -5,45 +5,20 @@ module Mutant
5
5
  class Noop < self
6
6
 
7
7
  # Literal references to self do not need to be mutated?
8
- handle(Rubinius::AST::Self)
8
+ handle(:self)
9
+
10
+ # These nodes still need a mutator, your contribution is that close!
11
+ handle(
12
+ :zsuper, :not, :or, :and, :defined,
13
+ :next, :break, :match, :gvar, :cvar, :ensure,
14
+ :dstr, :dsym, :yield, :rescue, :redo, :defined?,
15
+ :lvar, :splat, :const, :blockarg, :block_pass, :op_asgn, :regopt,
16
+ :ivar, :restarg, :casgn, :masgn, :resbody, :retry, :arg_expr,
17
+ :kwrestarg, :kwoptarg, :kwarg, :undef, :module, :cbase, :empty,
18
+ :alias, :for, :xstr, :back_ref, :nth_ref, :class, :sclass, :match_with_lvasgn,
19
+ :match_current_line, :or_asgn
20
+ )
9
21
 
10
- # Currently unhandled node classes. Feel free to contribute your mutator!
11
- handle(Rubinius::AST::ZSuper)
12
- handle(Rubinius::AST::ElementAssignment)
13
- handle(Rubinius::AST::AttributeAssignment)
14
- handle(Rubinius::AST::Not)
15
- handle(Rubinius::AST::And)
16
- handle(Rubinius::AST::Or)
17
- handle(Rubinius::AST::Defined)
18
- handle(Rubinius::AST::Super)
19
- handle(Rubinius::AST::Next)
20
- handle(Rubinius::AST::Break)
21
- handle(Rubinius::AST::Match3)
22
- handle(Rubinius::AST::ZSuper)
23
- handle(Rubinius::AST::MultipleAssignment)
24
- handle(Rubinius::AST::ScopedConstant)
25
- handle(Rubinius::AST::LocalVariableAccess)
26
- handle(Rubinius::AST::InstanceVariableAccess)
27
- handle(Rubinius::AST::GlobalVariableAccess)
28
- handle(Rubinius::AST::ClassVariableAccess)
29
- handle(Rubinius::AST::ToplevelConstant)
30
- handle(Rubinius::AST::Ensure)
31
- handle(Rubinius::AST::Rescue)
32
- handle(Rubinius::AST::DynamicString)
33
- handle(Rubinius::AST::DynamicSymbol)
34
- handle(Rubinius::AST::DynamicRegex)
35
- handle(Rubinius::AST::File)
36
- handle(Rubinius::AST::NthRef)
37
- handle(Rubinius::AST::OpAssignOr19)
38
- handle(Rubinius::AST::BlockPass19)
39
- handle(Rubinius::AST::OpAssign1)
40
- handle(Rubinius::AST::OpAssign2)
41
- handle(Rubinius::AST::SplatValue)
42
- handle(Rubinius::AST::ConstantAccess)
43
- handle(Rubinius::AST::Yield)
44
- handle(Rubinius::AST::Begin)
45
- handle(Rubinius::AST::Rescue)
46
-
47
22
  private
48
23
 
49
24
  # Emit mutations
@@ -53,9 +28,9 @@ module Mutant
53
28
  # @api private
54
29
  #
55
30
  def dispatch
56
- # noop
57
31
  end
58
- end
59
- end
60
- end
61
- end
32
+
33
+ end # Noop
34
+ end # Node
35
+ end # Mutator
36
+ end # Mutant
@@ -4,10 +4,11 @@ module Mutant
4
4
  # Mutator for return statements
5
5
  class Return < self
6
6
 
7
- handle(Rubinius::AST::Return)
7
+ handle(:return)
8
8
 
9
- private
9
+ children :value
10
10
 
11
+ private
11
12
 
12
13
  # Emit mutants
13
14
  #
@@ -16,16 +17,15 @@ module Mutant
16
17
  # @api private
17
18
  #
18
19
  def dispatch
19
- value = node.value
20
20
  if value
21
21
  emit(value)
22
+ emit_value_mutations
22
23
  else
23
24
  emit_nil
24
25
  end
25
26
  end
26
27
 
27
- end
28
- end
29
- end
30
-
31
- end
28
+ end # Return
29
+ end # Node
30
+ end # Mutator
31
+ end # Mutant
@@ -0,0 +1,31 @@
1
+ module Mutant
2
+ class Mutator
3
+ class Node
4
+ class Send
5
+
6
+ # Mutator for sends that correspond to a binary operator
7
+ class Binary < self
8
+
9
+ children :left, :operator, :right
10
+
11
+ private
12
+
13
+ # Emit mutations
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ #
19
+ def dispatch
20
+ emit(left)
21
+ emit_left_mutations
22
+ emit(right) unless right.type == :splat
23
+ emit_right_mutations
24
+ end
25
+
26
+ end # Binary
27
+
28
+ end # Send
29
+ end # Node
30
+ end # Mutator
31
+ end # Mutant
@@ -5,137 +5,171 @@ module Mutant
5
5
  # Namespace for send mutators
6
6
  class Send < self
7
7
 
8
- handle(Rubinius::AST::Send)
8
+ handle(:send)
9
+
10
+ children :receiver, :selector
11
+
12
+ INDEX_REFERENCE = :[]
13
+ INDEX_ASSIGN = :[]=
14
+ ASSIGN_SUFFIX = :'='
15
+
16
+ # Base mutator for index operations
17
+ class Index < self
18
+
19
+ # Mutator for index references
20
+ class Reference < self
21
+
22
+ # Perform dispatch
23
+ #
24
+ # @return [undefined]
25
+ #
26
+ # @api private
27
+ #
28
+ def dispatch
29
+ emit(receiver)
30
+ end
31
+
32
+ end # Reference
33
+
34
+ # Mutator for index assignments
35
+ class Assign < self
36
+
37
+ # Perform dispatch
38
+ #
39
+ # @return [undefined]
40
+ #
41
+ # @api private
42
+ #
43
+ def dispatch
44
+ emit(receiver)
45
+ end
46
+
47
+ end # Assign
48
+ end # Index
9
49
 
10
50
  private
11
51
 
12
- # Emit mutations
52
+ # Perform dispatch
13
53
  #
14
54
  # @return [undefined]
15
55
  #
16
56
  # @api private
17
57
  #
18
58
  def dispatch
19
- emit_receiver
20
- emit_implicit_self_receiver
21
- emit_receiver_mutations
22
- emit_block_mutations
23
- emit_block_absence_mutation
59
+ case selector
60
+ when INDEX_REFERENCE
61
+ run(Index::Reference)
62
+ when INDEX_ASSIGN
63
+ run(Index::Assign)
64
+ else
65
+ non_index_dispatch
66
+ end
24
67
  end
25
68
 
26
- # Emit receiver
69
+ # Perform non index dispatch
27
70
  #
28
71
  # @return [undefined]
29
72
  #
30
73
  # @api private
31
74
  #
32
- def emit_receiver
33
- unless to_self?
34
- emit(receiver)
75
+ def non_index_dispatch
76
+ if binary_operator?
77
+ run(Binary)
78
+ return
35
79
  end
80
+ normal_dispatch
36
81
  end
37
82
 
38
- # Emit block mutations
83
+ # Return arguments
39
84
  #
40
- # @return [undefined]
85
+ # @return [Enumerable<Parser::AST::Node>]
41
86
  #
42
87
  # @api private
43
88
  #
44
- def emit_block_mutations
45
- emit_attribute_mutations(:block) if node.block
46
- end
89
+ alias_method :arguments, :remaining_children
47
90
 
48
- # Emit receiver mutations
91
+ # Perform normal, non special case dispatch
49
92
  #
50
93
  # @return [undefined]
51
94
  #
52
95
  # @api private
53
96
  #
54
- def emit_receiver_mutations
55
- emit_attribute_mutations(:receiver)
97
+ def normal_dispatch
98
+ emit(receiver) if receiver
99
+ mutate_receiver
100
+ emit_argument_propagation
101
+ mutate_arguments
56
102
  end
57
103
 
58
- # Emit block absence mutation
104
+ # Test for binary operator
59
105
  #
60
- # @return [undefined]
106
+ # @return [true]
107
+ # if send is a binary operator
108
+ #
109
+ # @return [false]
110
+ # otherwise
61
111
  #
62
112
  # @api private
63
113
  #
64
- def emit_block_absence_mutation
65
- dup = dup_node
66
- dup.block = nil
67
- emit(dup)
114
+ def binary_operator?
115
+ arguments.one? && BINARY_METHOD_OPERATORS.include?(selector)
68
116
  end
69
117
 
70
- # Return receiver AST node
118
+ # Mutate arguments
71
119
  #
72
- # @return [Rubinius::AST::Node]
120
+ # @return [undefined]
73
121
  #
74
122
  # @api private
75
123
  #
76
- def receiver
77
- node.receiver
124
+ def mutate_arguments
125
+ return if arguments.empty?
126
+ emit_self(receiver, selector)
127
+ remaining_children_with_index.each do |node, index|
128
+ mutate_child(index)
129
+ delete_child(index)
130
+ end
78
131
  end
79
132
 
80
- # Return name of call
133
+ NO_PROPAGATE = [ :splat, :block_pass ].to_set
134
+
135
+ # Emit argument propagation
81
136
  #
82
- # @return [Symbol]
137
+ # @return [undefined]
83
138
  #
84
139
  # @api private
85
140
  #
86
- def name
87
- node.name
141
+ def emit_argument_propagation
142
+ return unless arguments.one?
143
+ node = arguments.first
144
+ return if NO_PROPAGATE.include?(node.type)
145
+ emit(arguments.first)
88
146
  end
89
147
 
90
- # Check if receiver is self
91
- #
92
- # @return [true]
93
- # if receiver is a Rubinius::AST::Self node
148
+ # Emit receiver mutations
94
149
  #
95
- # @return [false]
96
- # return false otherwise
150
+ # @return [undefined]
97
151
  #
98
152
  # @api private
99
153
  #
100
- def to_self?
101
- receiver.kind_of?(Rubinius::AST::Self)
154
+ def mutate_receiver
155
+ return unless receiver
156
+ emit_implicit_self
157
+ emit_receiver_mutations
102
158
  end
103
159
 
104
- # Emit mutation that replaces explicit send to self with implicit send to self
105
- #
106
- # @example:
107
- #
108
- # # This class does use Foo#a with explicitly specifing the receiver self.
109
- # # But an implicit (privately) call should be used as there is no need for
110
- # # specifing en explicit receiver.
111
- #
112
- # class Foo # Mutation
113
- # def print_a # def print_a
114
- # puts self.a # puts a
115
- # end # end
116
- #
117
- # def a
118
- # :bar
119
- # end
120
- # end
121
- #
122
- # There will not be any exception so the mutant is not killed and such calls where
123
- # implicit receiver should be used will be spotted.
160
+ # Emit implicit self mutation
124
161
  #
125
162
  # @return [undefined]
126
163
  #
127
164
  # @api private
128
165
  #
129
- def emit_implicit_self_receiver
130
- unless to_self? and !Mutant::KEYWORDS.include?(node.name)
131
- return
166
+ def emit_implicit_self
167
+ if receiver.type == :self and !KEYWORDS.include?(selector)
168
+ emit_receiver(nil)
132
169
  end
133
-
134
- mutant = dup_node
135
- mutant.privately = true
136
- emit(mutant)
137
170
  end
138
- end
139
- end
140
- end
141
- end
171
+
172
+ end # Send
173
+ end # Node
174
+ end # Mutator
175
+ end # Mutant