mutest 0.0.6 → 0.0.7

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 (119) hide show
  1. checksums.yaml +4 -4
  2. data/.buildkite/hooks/pre-command +1 -1
  3. data/.buildkite/pipeline.yml +9 -22
  4. data/.gitmodules +3 -0
  5. data/CHANGELOG.md +14 -1
  6. data/Gemfile +11 -6
  7. data/Gemfile.lock +27 -101
  8. data/README.md +42 -2
  9. data/Rakefile +2 -8
  10. data/circle.yml +4 -1
  11. data/lib/mutest.rb +1 -1
  12. data/lib/mutest/ast/meta/send.rb +6 -0
  13. data/lib/mutest/ast/named_children.rb +1 -1
  14. data/lib/mutest/ast/nodes.rb +0 -2
  15. data/lib/mutest/ast/regexp.rb +4 -4
  16. data/lib/mutest/ast/regexp/transformer.rb +4 -4
  17. data/lib/mutest/ast/regexp/transformer/character_set.rb +1 -1
  18. data/lib/mutest/ast/regexp/transformer/direct.rb +1 -1
  19. data/lib/mutest/ast/regexp/transformer/quantifier.rb +3 -3
  20. data/lib/mutest/ast/regexp/transformer/recursive.rb +1 -1
  21. data/lib/mutest/ast/regexp/transformer/text.rb +1 -1
  22. data/lib/mutest/ast/types.rb +0 -1
  23. data/lib/mutest/cli.rb +1 -1
  24. data/lib/mutest/context.rb +1 -1
  25. data/lib/mutest/matcher/config.rb +0 -2
  26. data/lib/mutest/matcher/method.rb +1 -3
  27. data/lib/mutest/matcher/method/instance.rb +1 -1
  28. data/lib/mutest/matcher/methods.rb +1 -1
  29. data/lib/mutest/mutator.rb +0 -2
  30. data/lib/mutest/mutator/node/block_pass.rb +29 -0
  31. data/lib/mutest/mutator/node/generic.rb +1 -0
  32. data/lib/mutest/mutator/node/literal/boolean.rb +0 -1
  33. data/lib/mutest/mutator/node/literal/range.rb +1 -1
  34. data/lib/mutest/mutator/node/literal/regex.rb +1 -1
  35. data/lib/mutest/mutator/node/literal/string.rb +3 -0
  36. data/lib/mutest/mutator/node/literal/symbol.rb +0 -2
  37. data/lib/mutest/mutator/node/send.rb +35 -6
  38. data/lib/mutest/mutator/node/splat.rb +3 -1
  39. data/lib/mutest/parallel/worker.rb +1 -1
  40. data/lib/mutest/reporter/cli.rb +0 -2
  41. data/lib/mutest/reporter/cli/format.rb +1 -1
  42. data/lib/mutest/reporter/cli/printer.rb +2 -2
  43. data/lib/mutest/reporter/cli/printer/mutation_result.rb +0 -2
  44. data/lib/mutest/version.rb +1 -1
  45. data/meta/and.rb +0 -2
  46. data/meta/array.rb +0 -3
  47. data/meta/begin.rb +0 -3
  48. data/meta/block.rb +0 -1
  49. data/meta/block_pass.rb +30 -1
  50. data/meta/break.rb +0 -1
  51. data/meta/case.rb +0 -6
  52. data/meta/casgn.rb +0 -3
  53. data/meta/cvasgn.rb +0 -1
  54. data/meta/def.rb +0 -7
  55. data/meta/dstr.rb +2 -0
  56. data/meta/dsym.rb +2 -0
  57. data/meta/ensure.rb +0 -1
  58. data/meta/false.rb +0 -1
  59. data/meta/gvasgn.rb +0 -1
  60. data/meta/hash.rb +0 -4
  61. data/meta/if.rb +0 -5
  62. data/meta/ivasgn.rb +0 -1
  63. data/meta/kwbegin.rb +0 -1
  64. data/meta/lvasgn.rb +0 -1
  65. data/meta/match_current_line.rb +0 -1
  66. data/meta/next.rb +0 -1
  67. data/meta/or.rb +0 -2
  68. data/meta/regexp.rb +0 -1
  69. data/meta/rescue.rb +0 -6
  70. data/meta/send.rb +60 -16
  71. data/meta/splat.rb +25 -0
  72. data/meta/str.rb +1 -0
  73. data/meta/true.rb +0 -1
  74. data/meta/until.rb +0 -1
  75. data/meta/while.rb +0 -2
  76. data/meta/yield.rb +0 -1
  77. data/mutest-rspec.gemspec +1 -1
  78. data/mutest.gemspec +0 -4
  79. data/spec/integration/mutest/rspec_spec.rb +1 -1
  80. data/spec/integrations.yml +1 -1
  81. data/spec/shared/command_method_behavior.rb +5 -0
  82. data/spec/shared/idempotent_method_behavior.rb +10 -0
  83. data/spec/spec_helper.rb +21 -1
  84. data/spec/support/xspec.rb +1 -1
  85. data/spec/unit/mutest/actor/sender_spec.rb +1 -1
  86. data/spec/unit/mutest/ast/meta/send_spec.rb +23 -11
  87. data/spec/unit/mutest/cli_spec.rb +13 -13
  88. data/spec/unit/mutest/context_spec.rb +2 -2
  89. data/spec/unit/mutest/diff_spec.rb +9 -9
  90. data/spec/unit/mutest/integration/null_spec.rb +1 -1
  91. data/spec/unit/mutest/integration_spec.rb +1 -1
  92. data/spec/unit/mutest/matcher/method/instance_spec.rb +5 -5
  93. data/spec/unit/mutest/matcher/method/singleton_spec.rb +5 -5
  94. data/spec/unit/mutest/meta/example_spec.rb +3 -3
  95. data/spec/unit/mutest/mutation_spec.rb +5 -5
  96. data/spec/unit/mutest/mutator/node_spec.rb +6 -9
  97. data/spec/unit/mutest/parallel/driver_spec.rb +1 -1
  98. data/spec/unit/mutest/reporter/null_spec.rb +1 -1
  99. data/spec/unit/mutest/reporter/sequence_spec.rb +1 -1
  100. data/spec/unit/mutest/result_spec.rb +1 -1
  101. data/spec/unit/mutest/runner/sink_spec.rb +1 -1
  102. data/spec/unit/mutest/subject/method/instance/memoized_spec.rb +1 -1
  103. data/spec/unit/mutest/subject/method/instance_spec.rb +3 -3
  104. data/spec/unit/mutest/subject/method/singleton_spec.rb +3 -3
  105. data/spec/unit/mutest/subject_spec.rb +2 -2
  106. data/test_app/Gemfile.rspec3.6 +7 -0
  107. metadata +9 -57
  108. data/build/Dockerfile +0 -71
  109. data/build/docker-bootstrap.sh +0 -85
  110. data/build/docker-exec +0 -29
  111. data/build/make-docker +0 -3
  112. data/build/ruby_matrix +0 -1
  113. data/build/run +0 -5
  114. data/build/strict-mode.sh +0 -16
  115. data/config/devtools.yml +0 -2
  116. data/config/flay.yml +0 -3
  117. data/config/flog.yml +0 -2
  118. data/config/reek.yml +0 -137
  119. data/lib/mutest/mutator/node/noop.rb +0 -19
@@ -1,8 +1,6 @@
1
1
  module Mutest
2
2
  module AST
3
3
  # Singleton nodes
4
- #
5
- # :reek:TooManyConstants
6
4
  module Nodes
7
5
  extend Sexp
8
6
 
@@ -10,14 +10,14 @@ module Mutest
10
10
  #
11
11
  # @param regexp [String]
12
12
  #
13
- # @return [Regexp::Expression]
13
+ # @return [Regexp::Expression::Base]
14
14
  def self.parse(regexp)
15
15
  ::Regexp::Parser.parse(regexp)
16
16
  end
17
17
 
18
18
  # Check if expression is supported by mapper
19
19
  #
20
- # @param expression [Regexp::Expression]
20
+ # @param expression [Regexp::Expression::Base]
21
21
  #
22
22
  # @return [Boolean]
23
23
  def self.supported?(expression)
@@ -28,7 +28,7 @@ module Mutest
28
28
 
29
29
  # Convert expression into ast node
30
30
  #
31
- # @param expression [Regexp::Expression]
31
+ # @param expression [Regexp::Expression::Base]
32
32
  #
33
33
  # @return [Parser::AST::Node]
34
34
  def self.to_ast(expression)
@@ -41,7 +41,7 @@ module Mutest
41
41
  #
42
42
  # @param node [Parser::AST::Node]
43
43
  #
44
- # @return [Regexp::Expression]
44
+ # @return [Regexp::Expression::Base]
45
45
  def self.to_expression(node)
46
46
  Transformer.lookup(node.type).to_expression(node)
47
47
  end
@@ -32,7 +32,7 @@ module Mutest
32
32
 
33
33
  # Transform expression
34
34
  #
35
- # @param expression [Regexp::Expression]
35
+ # @param expression [Regexp::Expression::Base]
36
36
  #
37
37
  # @return [Parser::AST::Node]
38
38
  def self.to_ast(expression)
@@ -43,7 +43,7 @@ module Mutest
43
43
  #
44
44
  # @param node [Parser::AST::Node]
45
45
  #
46
- # @return [Regexp::Expression]
46
+ # @return [Regexp::Expression::Base]
47
47
  def self.to_expression(node)
48
48
  self::ASTToExpression.call(node)
49
49
  end
@@ -101,7 +101,7 @@ module Mutest
101
101
 
102
102
  # Call generic transform method and freeze result
103
103
  #
104
- # @return [Regexp::Expression]
104
+ # @return [Regexp::Expression::Base]
105
105
  def call
106
106
  transform.freeze
107
107
  end
@@ -110,7 +110,7 @@ module Mutest
110
110
 
111
111
  # Transformation of ast into expression
112
112
  #
113
- # @return [Regexp::Expression]
113
+ # @return [Regexp::Expression::Base]
114
114
  abstract_method :transform
115
115
 
116
116
  # Transformed children of node
@@ -32,7 +32,7 @@ module Mutest
32
32
 
33
33
  # Transform node into expression
34
34
  #
35
- # @return [Regexp::Expression]
35
+ # @return [Regexp::Expression::Base]
36
36
  def transform
37
37
  CHARACTER_SET.dup.tap do |expression|
38
38
  expression.members = node.children
@@ -87,7 +87,7 @@ module Mutest
87
87
 
88
88
  # Transform ast into expression
89
89
  #
90
- # @return [Regexp::Expression]
90
+ # @return [Regexp::Expression::Base]
91
91
  def transform
92
92
  expression_class.new(expression_token)
93
93
  end
@@ -49,7 +49,7 @@ module Mutest
49
49
 
50
50
  # Transform ast into quantifier attached to expression
51
51
  #
52
- # @return [Regexp::Expression]
52
+ # @return [Regexp::Expression::Base]
53
53
  def transform
54
54
  Regexp.to_expression(subject).dup.tap do |expression|
55
55
  expression.quantify(type, text, min, max, mode)
@@ -69,7 +69,7 @@ module Mutest
69
69
 
70
70
  # Type of quantifier
71
71
  #
72
- # @return [:zero_or_more,:one_or_more,:interval]
72
+ # @return [Symbol] :zero_or_more, :one_or_more, or :interval
73
73
  def type
74
74
  quantifier.type
75
75
  end
@@ -83,7 +83,7 @@ module Mutest
83
83
 
84
84
  # The quantifier "mode"
85
85
  #
86
- # @return [:greedy,:possessive,:reluctant]
86
+ # @return [Symbol] :greedy, :possessive, or :reluctant
87
87
  def mode
88
88
  quantifier.mode
89
89
  end
@@ -34,7 +34,7 @@ module Mutest
34
34
 
35
35
  # Transform nodes and their children into expressions
36
36
  #
37
- # @return [Regexp::Expression]
37
+ # @return [Regexp::Expression::Base]
38
38
  def transform
39
39
  expression_class.new(expression_token).tap do |expression|
40
40
  expression.expressions = subexpressions
@@ -39,7 +39,7 @@ module Mutest
39
39
 
40
40
  # Transform node to expression with text value
41
41
  #
42
- # @return [Regexp::Expression]
42
+ # @return [Regexp::Expression::Base]
43
43
  def transform
44
44
  token = expression_token.dup
45
45
  token.text = Util.one(node.children)
@@ -2,7 +2,6 @@ module Mutest
2
2
  module AST
3
3
  # Groups of node types
4
4
  #
5
- # :reek:TooManyConstants
6
5
  # rubocop:disable Metrics/ModuleLength
7
6
  module Types
8
7
  symbolset = ->(strings) { strings.map(&:to_sym).to_set.freeze }
@@ -20,7 +20,7 @@ module Mutest
20
20
 
21
21
  # Initialize object
22
22
  #
23
- # @param [Array<String>]
23
+ # @param arguments [Array<String>]
24
24
  #
25
25
  # @return [undefined]
26
26
  def initialize(arguments)
@@ -74,7 +74,7 @@ module Mutest
74
74
 
75
75
  # Scope wrapped by context
76
76
  #
77
- # @return [Module|Class]
77
+ # @return [Module,Class]
78
78
  attr_reader :scope
79
79
 
80
80
  def ignore?(node)
@@ -1,8 +1,6 @@
1
1
  module Mutest
2
2
  class Matcher
3
3
  # Subject matcher configuration
4
- #
5
- # :reek:TooManyConstants
6
4
  class Config
7
5
  include Adamantium, Anima.new(
8
6
  :ignore_expressions,
@@ -1,8 +1,6 @@
1
1
  module Mutest
2
2
  class Matcher
3
3
  # Abstract base class for method matchers
4
- #
5
- # :reek:TooManyMethods { max_methods: 11 }
6
4
  class Method < self
7
5
  include AbstractType,
8
6
  Adamantium::Flat,
@@ -105,7 +103,7 @@ module Mutest
105
103
 
106
104
  # Full source location
107
105
  #
108
- # @return [Array{String,Fixnum}]
106
+ # @return [Array<String,Fixnum>]
109
107
  def source_location
110
108
  target_method.source_location
111
109
  end
@@ -47,7 +47,7 @@ module Mutest
47
47
 
48
48
  # Source location
49
49
  #
50
- # @return [Array{String,Fixnum}]
50
+ # @return [Array<String,Fixnum>]
51
51
  def source_location
52
52
  scope
53
53
  .unmemoized_instance_method(method_name)
@@ -27,7 +27,7 @@ module Mutest
27
27
 
28
28
  # method matcher class
29
29
  #
30
- # @return [Class:Matcher::Method]
30
+ # @return [Class] Matcher::Method
31
31
  def matcher
32
32
  self.class::MATCHER
33
33
  end
@@ -14,8 +14,6 @@ module Mutest
14
14
  # @param parent [nil,Mutest::Mutator::Node]
15
15
  #
16
16
  # @return [Set<Parser::AST::Node>]
17
- #
18
- # :reek:LongParameterList
19
17
  def self.mutate(node, filter = ->(_) {}, parent = nil)
20
18
  self::REGISTRY.lookup(node.type).call(node, filter, parent)
21
19
  end
@@ -0,0 +1,29 @@
1
+ module Mutest
2
+ class Mutator
3
+ class Node
4
+ class BlockPass < self
5
+ handle(:block_pass)
6
+
7
+ children :arg
8
+
9
+ private
10
+
11
+ # Emit mutations
12
+ #
13
+ # @return [undefined]
14
+ def dispatch
15
+ emit_arg_mutations
16
+ emit_symbol_to_proc_mutations
17
+ end
18
+
19
+ def emit_symbol_to_proc_mutations
20
+ return unless n_sym?(arg)
21
+
22
+ Send::SELECTOR_REPLACEMENTS.fetch(*arg, EMPTY_ARRAY).each do |method|
23
+ emit_arg(s(:sym, method))
24
+ end
25
+ end
26
+ end # BlockPass
27
+ end # Node
28
+ end # Mutator
29
+ end # Mutest
@@ -4,6 +4,7 @@ module Mutest
4
4
  # Generic mutator
5
5
  class Generic < self
6
6
  unsupported_nodes = %i[
7
+ cbase
7
8
  ensure
8
9
  redo
9
10
  retry
@@ -17,7 +17,6 @@ module Mutest
17
17
  #
18
18
  # @return [undefined]
19
19
  def dispatch
20
- emit_nil
21
20
  emit(s(MAP.fetch(node.type)))
22
21
  end
23
22
  end # Boolean
@@ -27,7 +27,7 @@ module Mutest
27
27
 
28
28
  # Inverse node
29
29
  #
30
- # @return [Parser::AST::Node]
30
+ # @return [undefined]
31
31
  def emit_inverse
32
32
  emit(s(MAP.fetch(node.type), *children))
33
33
  end
@@ -57,7 +57,7 @@ module Mutest
57
57
 
58
58
  # Expression representation of regexp body
59
59
  #
60
- # @return [Regexp::Expression]
60
+ # @return [Regexp::Expression::Base]
61
61
  def body_expression
62
62
  AST::Regexp.parse(body.map(&:children).join)
63
63
  end
@@ -6,6 +6,8 @@ module Mutest
6
6
  class String < self
7
7
  handle(:str)
8
8
 
9
+ children :value
10
+
9
11
  private
10
12
 
11
13
  # Emit mutations
@@ -13,6 +15,7 @@ module Mutest
13
15
  # @return [undefined]
14
16
  def dispatch
15
17
  emit_singletons
18
+ emit_type(value + Util::Symbol::POSTFIX)
16
19
  end
17
20
  end # String
18
21
  end # Literal
@@ -8,8 +8,6 @@ module Mutest
8
8
 
9
9
  children :value
10
10
 
11
- PREFIX = '__mutest__'.freeze
12
-
13
11
  private
14
12
 
15
13
  # Emit mutations
@@ -114,6 +114,7 @@ module Mutest
114
114
  #
115
115
  # @return [undefined]
116
116
  def emit_selector_specific_mutations
117
+ emit_method_method_selector_replacements
117
118
  emit_const_get_mutation
118
119
  emit_integer_mutation
119
120
  emit_array_mutation
@@ -132,7 +133,25 @@ module Mutest
132
133
  RECEIVER_SELECTOR_REPLACEMENTS
133
134
  .fetch(receiver.children.last, EMPTY_HASH)
134
135
  .fetch(selector, EMPTY_ARRAY)
135
- .each(&method(:emit_selector))
136
+ .each(&public_method(:emit_selector))
137
+ end
138
+
139
+ # Emit selector mutations for [public_]method calls
140
+ #
141
+ # - Mutates `foo.method(:to_s)` to `foo.method(:to_str)`
142
+ # - Mutates `foo.public_method('to_s')` to `foo.public_method('to_str')`
143
+ #
144
+ # @return [undefined]
145
+ def emit_method_method_selector_replacements
146
+ return unless meta.method_object_selector? && meta.arguments.one?
147
+
148
+ arg = Mutest::Util.one(meta.arguments)
149
+
150
+ return unless n_sym?(arg) || n_str?(arg)
151
+
152
+ selector_replacements(*arg).each do |replacement|
153
+ emit_type(receiver, selector, s(arg.type, replacement))
154
+ end
136
155
  end
137
156
 
138
157
  # Emit mutation from `!!foo` to `foo`
@@ -149,7 +168,7 @@ module Mutest
149
168
  #
150
169
  # @return [undefined]
151
170
  def emit_lambda_mutation
152
- emit(s(:send, nil, :lambda)) if meta.proc?
171
+ emit_type(nil, :lambda) if meta.proc?
153
172
  end
154
173
 
155
174
  # Emit mutation for `#dig`
@@ -167,7 +186,7 @@ module Mutest
167
186
 
168
187
  return emit(fetch_mutation) if tail.empty?
169
188
 
170
- emit(s(:send, fetch_mutation, :dig, *tail))
189
+ emit_type(fetch_mutation, :dig, *tail)
171
190
  end
172
191
 
173
192
  # Emit mutation `foo[n..-1]` -> `foo.drop(n)`
@@ -180,7 +199,7 @@ module Mutest
180
199
 
181
200
  return unless ending.eql?(s(:int, -1))
182
201
 
183
- emit(s(:send, receiver, :drop, start))
202
+ emit_type(receiver, :drop, start)
184
203
  end
185
204
 
186
205
  # Emit mutation from `to_i` to `Integer(...)`
@@ -189,7 +208,7 @@ module Mutest
189
208
  def emit_integer_mutation
190
209
  return unless selector.equal?(:to_i)
191
210
 
192
- emit(s(:send, nil, :Integer, receiver))
211
+ emit_type(nil, :Integer, receiver)
193
212
  end
194
213
 
195
214
  # Emit mutation from `Array(a)` to `[a]`
@@ -214,7 +233,7 @@ module Mutest
214
233
  #
215
234
  # @return [undefined]
216
235
  def emit_selector_replacement
217
- SELECTOR_REPLACEMENTS.fetch(selector, EMPTY_ARRAY).each(&method(:emit_selector))
236
+ selector_replacements(selector).each(&public_method(:emit_selector))
218
237
  end
219
238
 
220
239
  # Emit naked receiver mutation
@@ -267,6 +286,16 @@ module Mutest
267
286
  meta.attribute_assignment?
268
287
  )
269
288
  end
289
+
290
+ def selector_replacements(selector)
291
+ replacements = SELECTOR_REPLACEMENTS.fetch(selector.to_sym, EMPTY_ARRAY)
292
+
293
+ if selector.instance_of?(String)
294
+ replacements.map(&:to_s)
295
+ else
296
+ replacements
297
+ end
298
+ end
270
299
  end # Send
271
300
  end # Node
272
301
  end # Mutator
@@ -14,7 +14,9 @@ module Mutest
14
14
  # @return [undefined]
15
15
  def dispatch
16
16
  emit_singletons
17
- emit_expression_mutations
17
+ emit_expression_mutations do |node|
18
+ !n_nil?(node)
19
+ end
18
20
  emit(expression)
19
21
  end
20
22
  end # Splat
@@ -10,7 +10,7 @@ module Mutest
10
10
 
11
11
  # Run worker
12
12
  #
13
- # @param [Hash<Symbol, Object] attributes
13
+ # @param [Hash<Symbol, Object>] attributes
14
14
  #
15
15
  # @return [self]
16
16
  def self.run(attributes)
@@ -9,8 +9,6 @@ module Mutest
9
9
  # @param [IO] output
10
10
  #
11
11
  # @return [Reporter::CLI]
12
- #
13
- # :reek:ManualDispatch
14
12
  def self.build(output)
15
13
  tput = Tput.detect
16
14
  tty = output.respond_to?(:tty?) && output.tty?