mutant 0.14.2 → 0.15.0

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 (69) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/lib/mutant/ast/named_children.rb +0 -4
  4. data/lib/mutant/ast/nodes.rb +5 -0
  5. data/lib/mutant/ast/pattern/lexer.rb +0 -1
  6. data/lib/mutant/ast/structure.rb +10 -0
  7. data/lib/mutant/context.rb +2 -6
  8. data/lib/mutant/env.rb +8 -27
  9. data/lib/mutant/hooks.rb +2 -6
  10. data/lib/mutant/integration/null.rb +1 -3
  11. data/lib/mutant/integration.rb +2 -6
  12. data/lib/mutant/isolation/fork.rb +0 -2
  13. data/lib/mutant/matcher/method/instance.rb +2 -2
  14. data/lib/mutant/matcher/method.rb +0 -1
  15. data/lib/mutant/meta/example/verification.rb +0 -1
  16. data/lib/mutant/mutation/operators.rb +141 -44
  17. data/lib/mutant/mutation.rb +6 -18
  18. data/lib/mutant/mutator/node/and_asgn.rb +1 -0
  19. data/lib/mutant/mutator/node/binary.rb +5 -0
  20. data/lib/mutant/mutator/node/block.rb +10 -0
  21. data/lib/mutant/mutator/node/case_match.rb +46 -0
  22. data/lib/mutant/mutator/node/conditional_loop.rb +30 -1
  23. data/lib/mutant/mutator/node/define.rb +26 -0
  24. data/lib/mutant/mutator/node/defined.rb +1 -0
  25. data/lib/mutant/mutator/node/ensure.rb +24 -0
  26. data/lib/mutant/mutator/node/guard.rb +23 -0
  27. data/lib/mutant/mutator/node/in_pattern.rb +25 -0
  28. data/lib/mutant/mutator/node/literal/complex.rb +31 -0
  29. data/lib/mutant/mutator/node/literal/rational.rb +31 -0
  30. data/lib/mutant/mutator/node/literal/string.rb +1 -0
  31. data/lib/mutant/mutator/node/match_alt.rb +26 -0
  32. data/lib/mutant/mutator/node/match_pattern_p.rb +25 -0
  33. data/lib/mutant/mutator/node/op_asgn.rb +21 -1
  34. data/lib/mutant/mutator/node/or_asgn.rb +1 -4
  35. data/lib/mutant/mutator/node/regopt.rb +4 -6
  36. data/lib/mutant/mutator/node/rescue.rb +27 -0
  37. data/lib/mutant/mutator/node/send/binary.rb +45 -0
  38. data/lib/mutant/mutator/node/send.rb +23 -7
  39. data/lib/mutant/mutator/node/super.rb +2 -0
  40. data/lib/mutant/mutator/node/zsuper.rb +17 -0
  41. data/lib/mutant/mutator/node.rb +3 -9
  42. data/lib/mutant/mutator.rb +1 -3
  43. data/lib/mutant/parallel/connection.rb +9 -23
  44. data/lib/mutant/parallel/driver.rb +1 -5
  45. data/lib/mutant/parallel/source.rb +2 -1
  46. data/lib/mutant/parallel/worker.rb +8 -14
  47. data/lib/mutant/registry.rb +2 -1
  48. data/lib/mutant/reporter/cli/format.rb +4 -12
  49. data/lib/mutant/reporter/cli/printer.rb +2 -6
  50. data/lib/mutant/reporter/cli/progress_bar.rb +4 -12
  51. data/lib/mutant/reporter/cli.rb +6 -23
  52. data/lib/mutant/reporter/sequence.rb +1 -3
  53. data/lib/mutant/repository/diff.rb +1 -3
  54. data/lib/mutant/result.rb +16 -48
  55. data/lib/mutant/scope.rb +2 -6
  56. data/lib/mutant/segment.rb +1 -3
  57. data/lib/mutant/subject/method/instance.rb +3 -9
  58. data/lib/mutant/subject/method/metaclass.rb +1 -4
  59. data/lib/mutant/subject/method/singleton.rb +2 -8
  60. data/lib/mutant/subject/method.rb +3 -9
  61. data/lib/mutant/subject.rb +6 -18
  62. data/lib/mutant/timer.rb +2 -6
  63. data/lib/mutant/transform.rb +11 -33
  64. data/lib/mutant/usage.rb +6 -18
  65. data/lib/mutant/variable.rb +2 -6
  66. data/lib/mutant/world.rb +1 -3
  67. data/lib/mutant/zombifier.rb +3 -1
  68. data/lib/mutant.rb +8 -0
  69. metadata +39 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19ddb5cce03b640bb465057b2e6a0ee983b44b3990fff144dcd3a737b6e7ba5c
4
- data.tar.gz: c97e3a1ac3fc5f4e431e70e86ee477933f1fa59e9ce338308a785c7fdab990c5
3
+ metadata.gz: cdcb7051e04dfb3ff669e6f673f13837725981be61745b633fda8c00122bb439
4
+ data.tar.gz: bc51f9a72c0163a1bae7f56f56ce10a06cf825281d1248b380048237394e404c
5
5
  SHA512:
6
- metadata.gz: aca0d3b5772f1b1caf6d075779dd6b54e02a4109917bc85f69b84afb038060f4610306b5f95c47f19cf429d287ffb4913b4cd5d71c19777a3f00a3df7cc7904e
7
- data.tar.gz: 3dd977fa2018eac8935f471266af5fa77f1ca02095c130a3852f342fca3e2e099ab2cfabc75b746e3a44bcbbeeef9adf9979f92469e87df46227f98139fc859c
6
+ metadata.gz: 6482d04cf00047a75531c116439726545e2955b0a0df5a9104f855b29720d30d61cc7779b4adaca2982596544bf5b46dc7f34f9d42eb2f187c973bf4288051dc
7
+ data.tar.gz: a805ae81a1f767004c37305555778aab712f58684f0cee50bfe9428f6dd9ab8979796ffdcaa4436510e579752b2a7c2e6331b37dc4af3ced942f3ae67536c906
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.14.2
1
+ 0.15.0
@@ -55,10 +55,6 @@ module Mutant
55
55
  #
56
56
  # @return [undefined]
57
57
  def define_remaining_children(names)
58
- define_private_method(:remaining_children_with_index) do
59
- children.each_with_index.drop(names.length)
60
- end
61
-
62
58
  define_private_method(:remaining_children_indices) do
63
59
  children.each_index.drop(names.length)
64
60
  end
@@ -17,6 +17,11 @@ module Mutant
17
17
  N_SELF = s(:self)
18
18
  N_ZSUPER = s(:zsuper)
19
19
  N_EMPTY_SUPER = s(:super)
20
+ N_EMPTY_ARRAY = s(:array)
21
+ N_EMPTY_HASH = s(:hash)
22
+ N_EMPTY_STRING = s(:str, '')
23
+ N_ZERO_INTEGER = s(:int, 0)
24
+ N_ZERO_FLOAT = s(:float, 0.0)
20
25
 
21
26
  end # Nodes
22
27
  end # AST
@@ -3,7 +3,6 @@
3
3
  module Mutant
4
4
  class AST
5
5
  class Pattern
6
- # rubocop:disable Metrics/ClassLength
7
6
  class Lexer
8
7
  WHITESPACE = [' ', "\t", "\n"].to_set.freeze
9
8
  STRING_PATTERN = /\A[a-zA-Z][_a-zA-Z0-9]*\z/
@@ -463,6 +463,11 @@ module Mutant
463
463
  ),
464
464
  variable: nil
465
465
  ),
466
+ Node.new(
467
+ type: :if_guard,
468
+ fixed: Node.fixed([[Node::Fixed::Descendant, :condition]]),
469
+ variable: nil
470
+ ),
466
471
  Node.new(
467
472
  type: :in_pattern,
468
473
  fixed: Node.fixed(
@@ -849,6 +854,11 @@ module Mutant
849
854
  ),
850
855
  variable: nil
851
856
  ),
857
+ Node.new(
858
+ type: :unless_guard,
859
+ fixed: Node.fixed([[Node::Fixed::Descendant, :condition]]),
860
+ variable: nil
861
+ ),
852
862
  Node.new(
853
863
  type: :when,
854
864
  fixed: [Node::Fixed::Descendant.new(index: -1, name: :body)],
@@ -33,9 +33,7 @@ module Mutant
33
33
  end
34
34
  end
35
35
 
36
- def match_expressions
37
- scope.match_expressions
38
- end
36
+ def match_expressions = scope.match_expressions
39
37
 
40
38
  # Return root node for mutation
41
39
  #
@@ -47,9 +45,7 @@ module Mutant
47
45
  # Identification string
48
46
  #
49
47
  # @return [String]
50
- def identification
51
- scope.raw.name
52
- end
48
+ def identification = scope.raw.name
53
49
 
54
50
  end # Context
55
51
  end # Mutant
data/lib/mutant/env.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Mutant
4
4
  # Mutation testing execution environment
5
- # rubocop:disable Metrics/ClassLength
6
5
  class Env
7
6
  include Adamantium, Anima.new(
8
7
  :config,
@@ -93,57 +92,42 @@ module Mutant
93
92
  # @param [String] warning
94
93
  #
95
94
  # @return [self]
96
- def warn(message)
97
- config.reporter.warn(message)
98
- self
99
- end
95
+ def warn(message) = tap { config.reporter.warn(message) }
100
96
 
101
97
  # Selected tests
102
98
  #
103
99
  # @return [Set<Test>]
104
- def selected_tests
105
- selections.values.flatten.to_set
106
- end
100
+ def selected_tests = selections.values.flatten.to_set
107
101
  memoize :selected_tests
108
102
 
109
103
  # Amount of mutations
110
104
  #
111
105
  # @return [Integer]
112
- def amount_mutations
113
- mutations.length
114
- end
106
+ def amount_mutations = mutations.length
115
107
  memoize :amount_mutations
116
108
 
117
109
  # Amount of all tests the integration provides
118
110
  #
119
111
  # @return [Integer]
120
- def amount_all_tests
121
- integration.all_tests.length
122
- end
112
+ def amount_all_tests = integration.all_tests.length
123
113
  memoize :amount_all_tests
124
114
 
125
115
  # Amount of tests available for mutation testing
126
116
  #
127
117
  # @return [Integer]
128
- def amount_available_tests
129
- integration.available_tests.length
130
- end
118
+ def amount_available_tests = integration.available_tests.length
131
119
  memoize :amount_available_tests
132
120
 
133
121
  # Amount of selected subjects
134
122
  #
135
123
  # @return [Integer]
136
- def amount_subjects
137
- subjects.length
138
- end
124
+ def amount_subjects = subjects.length
139
125
  memoize :amount_subjects
140
126
 
141
127
  # Amount of selected tests
142
128
  #
143
129
  # @return [Integer]
144
- def amount_selected_tests
145
- selected_tests.length
146
- end
130
+ def amount_selected_tests = selected_tests.length
147
131
  memoize :amount_selected_tests
148
132
 
149
133
  # Ratio between selected tests and subjects
@@ -180,9 +164,6 @@ module Mutant
180
164
  end
181
165
  end
182
166
 
183
- def timer
184
- world.timer
185
- end
167
+ def timer = world.timer
186
168
  end # Env
187
- # rubocop:enable Metrics/ClassLength
188
169
  end # Mutant
data/lib/mutant/hooks.rb CHANGED
@@ -45,9 +45,7 @@ module Mutant
45
45
  end
46
46
 
47
47
  class Builder
48
- def initialize
49
- @map = DEFAULTS.transform_values(&:dup)
50
- end
48
+ def initialize = @map = DEFAULTS.transform_values(&:dup)
51
49
 
52
50
  def register(name, &block)
53
51
  Hooks.assert_name(name)
@@ -57,9 +55,7 @@ module Mutant
57
55
  self
58
56
  end
59
57
 
60
- def to_hooks
61
- Hooks.new(map: @map.transform_values(&:freeze).freeze)
62
- end
58
+ def to_hooks = Hooks.new(map: @map.transform_values(&:freeze).freeze)
63
59
  end # Builder
64
60
 
65
61
  # rubocop:disable Security/Eval
@@ -7,9 +7,7 @@ module Mutant
7
7
  # Available tests for integration
8
8
  #
9
9
  # @return [Enumerable<Test>]
10
- def all_tests
11
- EMPTY_ARRAY
12
- end
10
+ def all_tests = EMPTY_ARRAY
13
11
 
14
12
  # Run a collection of tests
15
13
  #
@@ -110,9 +110,7 @@ module Mutant
110
110
  # Perform integration setup
111
111
  #
112
112
  # @return [self]
113
- def setup
114
- self
115
- end
113
+ def setup = self
116
114
 
117
115
  # Run a collection of tests
118
116
  #
@@ -138,8 +136,6 @@ module Mutant
138
136
 
139
137
  private
140
138
 
141
- def timer
142
- world.timer
143
- end
139
+ def timer = world.timer
144
140
  end # Integration
145
141
  end # Mutant
@@ -64,7 +64,6 @@ module Mutant
64
64
  end
65
65
  end # Pipe
66
66
 
67
- # rubocop:disable Metrics/ClassLength
68
67
  class Parent
69
68
  include(Anima.new(*ATTRIBUTES), Procto)
70
69
 
@@ -206,7 +205,6 @@ module Mutant
206
205
  status
207
206
  end
208
207
  end # Parent
209
- # rubocop:enable Metrics/ClassLength
210
208
 
211
209
  class Child
212
210
  include(Adamantium, Anima.new(*ATTRIBUTES), Procto)
@@ -52,9 +52,9 @@ module Mutant
52
52
  end
53
53
 
54
54
  def visibility
55
- if scope.raw.private_instance_methods.include?(method_name)
55
+ if scope.raw.private_method_defined?(method_name)
56
56
  :private
57
- elsif scope.raw.protected_instance_methods.include?(method_name)
57
+ elsif scope.raw.protected_method_defined?(method_name)
58
58
  :protected
59
59
  else
60
60
  :public
@@ -34,7 +34,6 @@ module Mutant
34
34
  # logic would be implemented directly on the Matcher::Method
35
35
  # instance
36
36
  #
37
- # rubocop:disable Metrics/ClassLength
38
37
  class Evaluator
39
38
  include(
40
39
  AbstractType,
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Mutant
4
4
  module Meta
5
- # rubocop:disable Metrics/ClassLength
6
5
  class Example
7
6
  # Example verification
8
7
  class Verification
@@ -10,47 +10,146 @@ module Mutant
10
10
  NAME = :full
11
11
 
12
12
  SELECTOR_REPLACEMENTS = {
13
- :& => %i[| ^],
14
- :< => %i[== eql? equal?],
15
- :<< => %i[>>],
16
- :<= => %i[< == eql? equal?],
17
- :== => %i[eql? equal?],
18
- :=== => %i[is_a?],
19
- :=~ => %i[match?],
20
- :> => %i[== eql? equal?],
21
- :>= => %i[> == eql? equal?],
22
- :>> => %i[<<],
23
- :^ => %i[& |],
24
- :| => %i[& ^],
25
- __send__: %i[public_send],
26
- all?: %i[any?],
27
- any?: %i[all?],
28
- at: %i[fetch key?],
29
- detect: %i[first last],
30
- fetch: %i[key?],
31
- find: %i[first last],
32
- first: %i[last],
33
- flat_map: %i[map],
34
- gsub: %i[sub],
35
- is_a?: %i[instance_of?],
36
- kind_of?: %i[instance_of?],
37
- last: %i[first],
38
- map: %i[each],
39
- match: %i[match?],
40
- max: %i[first last],
41
- max_by: %i[first last],
42
- method: %i[public_method],
43
- min: %i[first last],
44
- min_by: %i[first last],
45
- reverse_each: %i[each],
46
- reverse_map: %i[map each],
47
- reverse_merge: %i[merge],
48
- send: %i[public_send __send__],
49
- to_a: %i[to_ary],
50
- to_h: %i[to_hash],
51
- to_i: %i[to_int],
52
- to_s: %i[to_str],
53
- values_at: %i[fetch_values]
13
+ :!= => %i[==],
14
+ :** => %i[*],
15
+ :% => %i[/],
16
+ :& => %i[| ^],
17
+ :* => %i[/],
18
+ :+ => %i[-],
19
+ :- => %i[+],
20
+ :/ => %i[*],
21
+ :< => %i[== eql? equal?],
22
+ :<< => %i[>>],
23
+ :<= => %i[< == eql? equal?],
24
+ :== => %i[!= eql? equal?],
25
+ :=== => %i[is_a?],
26
+ :=~ => %i[match?],
27
+ :> => %i[== eql? equal?],
28
+ :>= => %i[> == eql? equal?],
29
+ :>> => %i[<<],
30
+ :^ => %i[& |],
31
+ :| => %i[& ^],
32
+ __send__: %i[public_send],
33
+ all?: %i[any? none?],
34
+ any?: %i[all? empty? none?],
35
+ append: %i[prepend],
36
+ assoc: %i[rassoc],
37
+ at: %i[fetch key?],
38
+ bytes: %i[chars],
39
+ # Bang to non-bang mutations (Array methods)
40
+ capitalize!: %i[capitalize],
41
+ chars: %i[bytes],
42
+ chomp!: %i[chomp],
43
+ chop!: %i[chop],
44
+ chunk: %i[each],
45
+ chunk_while: %i[each],
46
+ collect: %i[each],
47
+ collect!: %i[collect],
48
+ collect_concat: %i[collect],
49
+ compact!: %i[compact],
50
+ ceil: %i[floor],
51
+ count: %i[size length],
52
+ delete!: %i[delete],
53
+ delete_if: %i[reject],
54
+ detect: %i[first last],
55
+ downcase: %i[upcase],
56
+ downcase!: %i[downcase],
57
+ drop: %i[take],
58
+ each_key: %i[each_value],
59
+ each_cons: %i[each],
60
+ each_slice: %i[each],
61
+ each_with_index: %i[each],
62
+ each_value: %i[each_key],
63
+ each_with_object: %i[each],
64
+ empty?: %i[any?],
65
+ encode!: %i[encode],
66
+ end_with?: %i[start_with?],
67
+ even?: %i[odd?],
68
+ fetch: %i[key?],
69
+ filter: %i[reject],
70
+ filter!: %i[filter],
71
+ filter_map: %i[map],
72
+ find: %i[first last],
73
+ first: %i[last],
74
+ flat_map: %i[map],
75
+ flatten!: %i[flatten],
76
+ floor: %i[ceil],
77
+ grep: %i[grep_v],
78
+ grep_v: %i[grep],
79
+ gsub: %i[sub],
80
+ gsub!: %i[gsub],
81
+ is_a?: %i[instance_of?],
82
+ keep_if: %i[select],
83
+ keys: %i[values],
84
+ kind_of?: %i[instance_of?],
85
+ last: %i[first],
86
+ lstrip!: %i[lstrip],
87
+ map: %i[each],
88
+ map!: %i[map],
89
+ match: %i[match?],
90
+ max: %i[first last min],
91
+ max_by: %i[first last min_by],
92
+ merge!: %i[merge],
93
+ method: %i[public_method],
94
+ min: %i[first last max],
95
+ min_by: %i[first last max_by],
96
+ negative?: %i[positive?],
97
+ none?: %i[any? all?],
98
+ odd?: %i[even?],
99
+ pop: %i[shift],
100
+ positive?: %i[negative?],
101
+ pred: %i[succ],
102
+ prepend: %i[append],
103
+ push: %i[unshift],
104
+ reject: %i[select],
105
+ reject!: %i[reject],
106
+ reverse!: %i[reverse],
107
+ reverse_each: %i[each],
108
+ reverse_map: %i[map each],
109
+ reverse_merge: %i[merge],
110
+ rotate!: %i[rotate],
111
+ rstrip!: %i[rstrip],
112
+ sample: %i[first last],
113
+ scrub!: %i[scrub],
114
+ rassoc: %i[assoc],
115
+ select: %i[reject],
116
+ select!: %i[select],
117
+ send: %i[public_send __send__],
118
+ shift: %i[pop],
119
+ shuffle!: %i[shuffle],
120
+ slice_after: %i[each],
121
+ slice_before: %i[each],
122
+ slice_when: %i[each],
123
+ sort!: %i[sort],
124
+ sort_by: %i[sort],
125
+ sort_by!: %i[sort_by],
126
+ squeeze!: %i[squeeze],
127
+ start_with?: %i[end_with?],
128
+ strip: %i[lstrip rstrip],
129
+ strip!: %i[strip],
130
+ sub!: %i[sub],
131
+ succ: %i[pred],
132
+ swapcase!: %i[swapcase],
133
+ take: %i[drop],
134
+ to_a: %i[to_ary],
135
+ to_f: %i[to_i],
136
+ to_h: %i[to_hash],
137
+ to_i: %i[to_int],
138
+ to_s: %i[to_str],
139
+ tr!: %i[tr],
140
+ tr_s!: %i[tr_s],
141
+ transform_keys: %i[transform_values],
142
+ transform_keys!: %i[transform_keys],
143
+ transform_values: %i[transform_keys],
144
+ transform_values!: %i[transform_values],
145
+ unicode_normalize!: %i[unicode_normalize],
146
+ uniq!: %i[uniq],
147
+ unshift: %i[push],
148
+ upcase: %i[downcase],
149
+ upcase!: %i[upcase],
150
+ values: %i[keys],
151
+ values_at: %i[fetch_values],
152
+ zero?: %i[nonzero?]
54
153
  }.freeze.tap { |hash| hash.each_value(&:freeze) }
55
154
  end
56
155
 
@@ -72,9 +171,7 @@ module Mutant
72
171
  self::NAME
73
172
  end
74
173
 
75
- def selector_replacements
76
- self.class::SELECTOR_REPLACEMENTS
77
- end
174
+ def selector_replacements = self.class::SELECTOR_REPLACEMENTS
78
175
 
79
176
  def self.parse(value)
80
177
  klass = [Light, Full].detect { |candidate| candidate.operators_name.to_s.eql?(value) }
@@ -70,33 +70,25 @@ module Mutant
70
70
  # Mutation identification code
71
71
  #
72
72
  # @return [String]
73
- def code
74
- sha1[CODE_RANGE]
75
- end
73
+ def code = sha1[CODE_RANGE]
76
74
  memoize :code
77
75
 
78
76
  # Identification string
79
77
  #
80
78
  # @return [String]
81
- def identification
82
- "#{self.class::SYMBOL}:#{subject.identification}:#{code}"
83
- end
79
+ def identification = "#{self.class::SYMBOL}:#{subject.identification}:#{code}"
84
80
  memoize :identification
85
81
 
86
82
  # The monkeypatch to insert the mutation
87
83
  #
88
84
  # @return [String]
89
- def monkeypatch
90
- Unparser.unparse(subject.context.root(node))
91
- end
85
+ def monkeypatch = Unparser.unparse(subject.context.root(node))
92
86
  memoize :monkeypatch
93
87
 
94
88
  # Normalized original source
95
89
  #
96
90
  # @return [String]
97
- def original_source
98
- subject.source
99
- end
91
+ def original_source = subject.source
100
92
 
101
93
  # Test if mutation is killed by test reports
102
94
  #
@@ -125,16 +117,12 @@ module Mutant
125
117
  end
126
118
  end
127
119
 
128
- def diff
129
- Unparser::Diff.build(original_source, source)
130
- end
120
+ def diff = Unparser::Diff.build(original_source, source)
131
121
  memoize :diff
132
122
 
133
123
  private
134
124
 
135
- def sha1
136
- Digest::SHA1.hexdigest(subject.identification + CODE_DELIMITER + source)
137
- end
125
+ def sha1 = Digest::SHA1.hexdigest(subject.identification + CODE_DELIMITER + source)
138
126
 
139
127
  # Evil mutation that should case mutations to fail tests
140
128
  class Evil < self
@@ -16,6 +16,7 @@ module Mutant
16
16
  def dispatch
17
17
  emit_left_mutations
18
18
  emit_right_mutations
19
+ emit(s(:or_asgn, *children))
19
20
  end
20
21
 
21
22
  end # AndAsgn
@@ -20,6 +20,7 @@ module Mutant
20
20
  def dispatch
21
21
  emit_singletons unless left_lvasgn?
22
22
  emit_promotions
23
+ emit_operator_swap
23
24
 
24
25
  emit_left_mutations do |mutation|
25
26
  !(n_irange?(mutation) || n_erange?(mutation)) || !mutation.children.fetch(1).nil?
@@ -28,6 +29,10 @@ module Mutant
28
29
  emit_right_mutations
29
30
  end
30
31
 
32
+ def emit_operator_swap
33
+ emit(s(INVERSE.fetch(node.type), left, right))
34
+ end
35
+
31
36
  def emit_promotions
32
37
  emit(left)
33
38
  emit(right) unless left_lvasgn?
@@ -14,12 +14,22 @@ module Mutant
14
14
  def dispatch
15
15
  emit_singletons
16
16
  emit(send) unless n_lambda?(send)
17
+ emit_receiver_promotion
17
18
  emit_send_mutations(&method(:valid_send_mutation?))
18
19
  emit_arguments_mutations
19
20
 
20
21
  mutate_body
21
22
  end
22
23
 
24
+ def emit_receiver_promotion
25
+ return unless n_send?(send)
26
+
27
+ send_meta = AST::Meta::Send.new(node: send)
28
+ return unless send_meta.receiver
29
+
30
+ emit(send_meta.receiver)
31
+ end
32
+
23
33
  def mutate_body
24
34
  emit_body(nil) unless unconditional_loop?
25
35
  emit_body(N_RAISE)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ class Mutator
5
+ class Node
6
+
7
+ # Mutator for case/in pattern matching nodes
8
+ class CaseMatch < self
9
+
10
+ handle(:case_match)
11
+
12
+ children :condition
13
+
14
+ define_named_child(:else_branch, -1)
15
+
16
+ PATTERNS = (1..-2)
17
+
18
+ private
19
+
20
+ def dispatch
21
+ emit_condition_mutations
22
+ emit_in_pattern_mutations
23
+ emit_else_mutations
24
+ end
25
+
26
+ def emit_in_pattern_mutations
27
+ indices = children_indices(PATTERNS)
28
+ one = indices.one?
29
+
30
+ indices.each do |index|
31
+ mutate_child(index)
32
+ delete_child(index) unless one
33
+ end
34
+ end
35
+
36
+ def emit_else_mutations
37
+ return unless else_branch
38
+
39
+ emit_else_branch_mutations
40
+ emit_else_branch(nil)
41
+ end
42
+
43
+ end # CaseMatch
44
+ end # Node
45
+ end # Mutator
46
+ end # Mutant