mutant 0.5.23 → 0.5.24

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 (89) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +10 -0
  3. data/config/flay.yml +1 -1
  4. data/config/reek.yml +19 -19
  5. data/lib/mutant.rb +12 -39
  6. data/lib/mutant/ast.rb +5 -0
  7. data/lib/mutant/ast/meta.rb +131 -0
  8. data/lib/mutant/ast/named_children.rb +98 -0
  9. data/lib/mutant/ast/node_predicates.rb +19 -0
  10. data/lib/mutant/ast/nodes.rb +21 -0
  11. data/lib/mutant/ast/sexp.rb +34 -0
  12. data/lib/mutant/ast/types.rb +48 -0
  13. data/lib/mutant/cache.rb +3 -2
  14. data/lib/mutant/cli.rb +11 -151
  15. data/lib/mutant/config.rb +22 -2
  16. data/lib/mutant/context/scope.rb +11 -21
  17. data/lib/mutant/delegator.rb +2 -0
  18. data/lib/mutant/diff.rb +7 -3
  19. data/lib/mutant/env.rb +49 -0
  20. data/lib/mutant/expression.rb +36 -8
  21. data/lib/mutant/expression/methods.rb +62 -0
  22. data/lib/mutant/expression/namespace.rb +41 -28
  23. data/lib/mutant/{strategy.rb → integration.rb} +12 -31
  24. data/lib/mutant/isolation.rb +1 -1
  25. data/lib/mutant/matcher.rb +1 -21
  26. data/lib/mutant/matcher/builder.rb +142 -0
  27. data/lib/mutant/matcher/method.rb +3 -7
  28. data/lib/mutant/matcher/method/instance.rb +6 -5
  29. data/lib/mutant/matcher/method/singleton.rb +2 -7
  30. data/lib/mutant/matcher/methods.rb +11 -14
  31. data/lib/mutant/matcher/namespace.rb +31 -39
  32. data/lib/mutant/matcher/scope.rb +13 -2
  33. data/lib/mutant/meta.rb +0 -1
  34. data/lib/mutant/meta/example/dsl.rb +5 -1
  35. data/lib/mutant/mutator/node.rb +16 -44
  36. data/lib/mutant/mutator/node/or_asgn.rb +1 -1
  37. data/lib/mutant/mutator/node/send.rb +5 -60
  38. data/lib/mutant/mutator/node/super.rb +2 -5
  39. data/lib/mutant/mutator/registry.rb +1 -1
  40. data/lib/mutant/reporter.rb +10 -0
  41. data/lib/mutant/reporter/cli.rb +13 -0
  42. data/lib/mutant/reporter/cli/printer.rb +2 -0
  43. data/lib/mutant/reporter/cli/progress/config.rb +1 -1
  44. data/lib/mutant/reporter/cli/progress/noop.rb +2 -0
  45. data/lib/mutant/reporter/cli/registry.rb +2 -0
  46. data/lib/mutant/reporter/null.rb +12 -0
  47. data/lib/mutant/reporter/trace.rb +4 -0
  48. data/lib/mutant/require_highjack.rb +2 -2
  49. data/lib/mutant/rspec.rb +0 -0
  50. data/lib/mutant/runner.rb +2 -0
  51. data/lib/mutant/runner/config.rb +8 -8
  52. data/lib/mutant/runner/killer.rb +5 -0
  53. data/lib/mutant/runner/subject.rb +1 -1
  54. data/lib/mutant/subject.rb +8 -8
  55. data/lib/mutant/subject/method.rb +3 -2
  56. data/lib/mutant/subject/method/instance.rb +1 -1
  57. data/lib/mutant/test.rb +7 -65
  58. data/lib/mutant/test/report.rb +59 -0
  59. data/lib/mutant/version.rb +1 -1
  60. data/lib/mutant/warning_filter.rb +2 -0
  61. data/lib/mutant/zombifier.rb +3 -0
  62. data/lib/mutant/zombifier/file.rb +1 -1
  63. data/meta/or_asgn.rb +11 -0
  64. data/meta/send.rb +1 -1
  65. data/mutant-rspec.gemspec +1 -1
  66. data/mutant.gemspec +1 -1
  67. data/spec/integration/mutant/corpus_spec.rb +2 -0
  68. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +2 -2
  69. data/spec/spec_helper.rb +4 -3
  70. data/spec/unit/mutant/cli_new_spec.rb +11 -11
  71. data/spec/unit/mutant/expression/methods_spec.rb +43 -0
  72. data/spec/unit/mutant/expression/namespace/flat_spec.rb +1 -1
  73. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +19 -5
  74. data/spec/unit/mutant/{strategy_spec.rb → integration_spec.rb} +1 -1
  75. data/spec/unit/mutant/isolation_spec.rb +3 -1
  76. data/spec/unit/mutant/matcher/method/instance_spec.rb +5 -5
  77. data/spec/unit/mutant/matcher/method/singleton_spec.rb +8 -8
  78. data/spec/unit/mutant/matcher/methods/instance_spec.rb +5 -8
  79. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +5 -5
  80. data/spec/unit/mutant/matcher/namespace_spec.rb +18 -23
  81. data/spec/unit/mutant/mutation_spec.rb +1 -1
  82. data/spec/unit/mutant/runner/config_spec.rb +4 -5
  83. data/spec/unit/mutant/runner/mutation_spec.rb +21 -21
  84. data/spec/unit/mutant/runner/subject_spec.rb +6 -6
  85. data/spec/unit/mutant/subject/method/instance_spec.rb +0 -4
  86. data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -1
  87. data/spec/unit/mutant/subject_spec.rb +3 -3
  88. metadata +20 -6
  89. data/lib/mutant/node_helpers.rb +0 -52
@@ -4,7 +4,7 @@ module Mutant
4
4
 
5
5
  # Example DSL
6
6
  class DSL
7
- include NodeHelpers
7
+ include AST::Sexp
8
8
 
9
9
  # Run DSL on block
10
10
  #
@@ -51,6 +51,8 @@ module Mutant
51
51
  #
52
52
  # @return [self]
53
53
  #
54
+ # @api private
55
+ #
54
56
  def source(input)
55
57
  raise 'source already defined' if @source
56
58
  @source = node(input)
@@ -64,6 +66,8 @@ module Mutant
64
66
  #
65
67
  # @return [self]
66
68
  #
69
+ # @api private
70
+ #
67
71
  def mutation(input)
68
72
  node = node(input)
69
73
  if @expected.include?(node)
@@ -5,11 +5,13 @@ module Mutant
5
5
 
6
6
  # Abstract base class for node mutators
7
7
  class Node < self
8
- include AbstractType, NodeHelpers, Unparser::Constants
8
+ include AbstractType, Unparser::Constants
9
+ include AST::NamedChildren, AST::NodePredicates, AST::Sexp, AST::Nodes
9
10
 
10
- # Define named child
11
+ # Helper to define a named child
12
+ #
13
+ # @param [Parser::AST::Node] node
11
14
  #
12
- # @param [Symbol] name
13
15
  # @param [Fixnum] index
14
16
  #
15
17
  # @return [undefined]
@@ -17,9 +19,7 @@ module Mutant
17
19
  # @api private
18
20
  #
19
21
  def self.define_named_child(name, index)
20
- define_method(name) do
21
- children.at(index)
22
- end
22
+ super
23
23
 
24
24
  define_method("emit_#{name}_mutations") do |&block|
25
25
  mutate_child(index, &block)
@@ -29,43 +29,6 @@ module Mutant
29
29
  emit_child_update(index, node)
30
30
  end
31
31
  end
32
- private_class_method :define_named_child
33
-
34
- # Define remaining children
35
- #
36
- # @param [Array<Symbol>] names
37
- #
38
- # @return [undefined]
39
- #
40
- # @api private
41
- #
42
- def self.define_remaining_children(names)
43
- define_method(:remaining_children_with_index) do
44
- children.each_with_index.drop(names.length)
45
- end
46
-
47
- define_method(:remaining_children_indices) do
48
- children.each_index.drop(names.length)
49
- end
50
-
51
- define_method(:remaining_children) do
52
- children.drop(names.length)
53
- end
54
- end
55
- private_class_method :define_remaining_children
56
-
57
- # Create name helpers
58
- #
59
- # @return [undefined]
60
- #
61
- # @api private
62
- #
63
- def self.children(*names)
64
- names.each_with_index do |name, index|
65
- define_named_child(name, index)
66
- end
67
- define_remaining_children(names)
68
- end
69
32
  private_class_method :children
70
33
 
71
34
  private
@@ -98,6 +61,15 @@ module Mutant
98
61
  end
99
62
  end
100
63
 
64
+ # Return ast meta description
65
+ #
66
+ # @return [AST::Meta]
67
+ #
68
+ def meta
69
+ AST::Meta.for(node)
70
+ end
71
+ memoize :meta
72
+
101
73
  # Return children
102
74
  #
103
75
  # @return [Array<Parser::AST::Node>]
@@ -246,7 +218,7 @@ module Mutant
246
218
  # @api private
247
219
  #
248
220
  def asgn_left?
249
- OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
221
+ AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
250
222
  end
251
223
 
252
224
  end # Node
@@ -22,7 +22,7 @@ module Mutant
22
22
  emit_right_mutations
23
23
  return if n_ivasgn?(left)
24
24
  emit_left_mutations do |node|
25
- !n_self?(node)
25
+ AST::Meta.for(node).assignment?
26
26
  end
27
27
  end
28
28
 
@@ -4,6 +4,7 @@ module Mutant
4
4
 
5
5
  # Namespace for send mutators
6
6
  class Send < self
7
+ include AST::Types
7
8
 
8
9
  handle(:send)
9
10
 
@@ -19,12 +20,6 @@ module Mutant
19
20
  :== => [:eql?, :equal?]
20
21
  )
21
22
 
22
- INDEX_REFERENCE = :[]
23
- INDEX_ASSIGN = :[]=
24
- VARIABLE_ASSIGN = :'='
25
- ASSIGNMENT_OPERATORS = [INDEX_ASSIGN, VARIABLE_ASSIGN].to_set.freeze
26
- ATTRIBUTE_ASSIGNMENT = /\A[a-z\d_]+=\z/.freeze
27
-
28
23
  private
29
24
 
30
25
  # Perform dispatch
@@ -35,7 +30,7 @@ module Mutant
35
30
  #
36
31
  def dispatch
37
32
  emit_singletons
38
- if selector.equal?(INDEX_ASSIGN)
33
+ if meta.index_assignment?
39
34
  run(Index::Assign)
40
35
  else
41
36
  non_index_dispatch
@@ -50,9 +45,9 @@ module Mutant
50
45
  #
51
46
  def non_index_dispatch
52
47
  case
53
- when binary_operator?
48
+ when meta.binary_method_operator?
54
49
  run(Binary)
55
- when attribute_assignment?
50
+ when meta.attribute_assignment?
56
51
  run(AttributeAssignment)
57
52
  else
58
53
  normal_dispatch
@@ -103,26 +98,6 @@ module Mutant
103
98
  emit(receiver) if receiver && !NOT_ASSIGNABLE.include?(receiver.type)
104
99
  end
105
100
 
106
- # Test for binary operator
107
- #
108
- # @return [Boolean]
109
- #
110
- # @api private
111
- #
112
- def binary_operator?
113
- arguments.one? && BINARY_METHOD_OPERATORS.include?(selector)
114
- end
115
-
116
- # Test for attribute assignment
117
- #
118
- # @return [Boolean]
119
- #
120
- # @api private
121
- #
122
- def attribute_assignment?
123
- arguments.one? && ATTRIBUTE_ASSIGNMENT =~ selector
124
- end
125
-
126
101
  # Mutate arguments
127
102
  #
128
103
  # @return [undefined]
@@ -173,40 +148,10 @@ module Mutant
173
148
  KEYWORDS.include?(selector) ||
174
149
  METHOD_OPERATORS.include?(selector) ||
175
150
  OP_ASSIGN.include?(parent_type) ||
176
- attribute_assignment?
151
+ meta.attribute_assignment?
177
152
  )
178
153
  end
179
154
 
180
- # Test for assignment
181
- #
182
- # @return [Boolean]
183
- #
184
- # @api private
185
- #
186
- def assignment?
187
- arguments.one? && (ASSIGNMENT_OPERATORS.include?(selector) || attribute_assignment?)
188
- end
189
-
190
- # Test if node is part of an mlhs
191
- #
192
- # @return [Boolean]
193
- #
194
- # @api private
195
- #
196
- def mlhs?
197
- assignment? && !arguments?
198
- end
199
-
200
- # Test for empty arguments
201
- #
202
- # @return [Boolean]
203
- #
204
- # @api private
205
- #
206
- def arguments?
207
- arguments.any?
208
- end
209
-
210
155
  end # Send
211
156
  end # Node
212
157
  end # Mutator
@@ -7,9 +7,6 @@ module Mutant
7
7
 
8
8
  handle(:super)
9
9
 
10
- Z_SUPER = NodeHelpers.s(:zsuper)
11
- EMPTY_SUPER = NodeHelpers.s(:super)
12
-
13
10
  private
14
11
 
15
12
  # Emit mutations
@@ -20,8 +17,8 @@ module Mutant
20
17
  #
21
18
  def dispatch
22
19
  emit_singletons
23
- emit(Z_SUPER)
24
- emit(EMPTY_SUPER)
20
+ emit(N_ZSUPER)
21
+ emit(N_EMPTY_SUPER)
25
22
  children.each_index do |index|
26
23
  mutate_child(index)
27
24
  delete_child(index)
@@ -64,7 +64,7 @@ module Mutant
64
64
  # @api private
65
65
  #
66
66
  def self.assert_valid_type(type)
67
- unless NODE_TYPES.include?(type) || type.kind_of?(Class)
67
+ unless AST::Types::ALL.include?(type) || type.kind_of?(Class)
68
68
  raise InvalidTypeError, "invalid type registration: #{type}"
69
69
  end
70
70
  end
@@ -3,6 +3,16 @@ module Mutant
3
3
  class Reporter
4
4
  include Adamantium::Flat, AbstractType
5
5
 
6
+ # Write warning message
7
+ #
8
+ # @param [String] message
9
+ #
10
+ # @return [self]
11
+ #
12
+ # @api private
13
+ #
14
+ abstract_method :warn
15
+
6
16
  # Report object
7
17
  #
8
18
  # @param [Object] object
@@ -19,6 +19,19 @@ module Mutant
19
19
  self
20
20
  end
21
21
 
22
+ # Report warning
23
+ #
24
+ # @param [String] message
25
+ #
26
+ # @return [self]
27
+ #
28
+ # @api private
29
+ #
30
+ def warn(message)
31
+ output.puts(message)
32
+ self
33
+ end
34
+
22
35
  # Report object
23
36
  #
24
37
  # @param [Object] object
@@ -13,6 +13,8 @@ module Mutant
13
13
  #
14
14
  # @return [self]
15
15
  #
16
+ # @api private
17
+ #
16
18
  def self.run(output, object)
17
19
  handler = lookup(object.class)
18
20
  handler.new(output, object).run
@@ -21,7 +21,7 @@ module Mutant
21
21
  if running?
22
22
  info 'Mutant configuration:'
23
23
  info 'Matcher: %s', config.matcher.inspect
24
- info 'Strategy: %s', config.strategy.inspect
24
+ info 'Integration: %s', config.integration.name
25
25
  info 'Expect Coverage: %0.2f%%', config.expected_coverage.inspect
26
26
  end
27
27
  self
@@ -11,6 +11,8 @@ module Mutant
11
11
  #
12
12
  # @return [self]
13
13
  #
14
+ # @api private
15
+ #
14
16
  def run
15
17
  self
16
18
  end
@@ -58,6 +58,8 @@ module Mutant
58
58
  #
59
59
  # @return [undefined]
60
60
  #
61
+ # @api private
62
+ #
61
63
  def included(host)
62
64
  object = self
63
65
  host.class_eval do
@@ -5,6 +5,18 @@ module Mutant
5
5
  class Null < self
6
6
  include Equalizer.new
7
7
 
8
+ # Write warning message
9
+ #
10
+ # @param [String] _message
11
+ #
12
+ # @return [self]
13
+ #
14
+ # @api private
15
+ #
16
+ def report(_message)
17
+ self
18
+ end
19
+
8
20
  # Report object
9
21
  #
10
22
  # @param [Object] _object
@@ -20,6 +20,8 @@ module Mutant
20
20
  #
21
21
  # @return [self]
22
22
  #
23
+ # @api private
24
+ #
23
25
  def report(object)
24
26
  report_calls << object
25
27
  self
@@ -31,6 +33,8 @@ module Mutant
31
33
  #
32
34
  # @return [self]
33
35
  #
36
+ # @api private
37
+ #
34
38
  def progress(object)
35
39
  progress_calls << object
36
40
  self
@@ -15,7 +15,7 @@ module Mutant
15
15
  #
16
16
  # @return [self]
17
17
  #
18
- # @api pivate
18
+ # @api private
19
19
  #
20
20
  def run
21
21
  infect
@@ -29,7 +29,7 @@ module Mutant
29
29
  #
30
30
  # @return [self]
31
31
  #
32
- # @api pivate
32
+ # @api private
33
33
  #
34
34
  def infect
35
35
  callback = @callback
File without changes
@@ -57,6 +57,8 @@ module Mutant
57
57
  #
58
58
  # @return [Boolean]
59
59
  #
60
+ # @api private
61
+ #
60
62
  def running?
61
63
  @running
62
64
  end
@@ -52,14 +52,14 @@ module Mutant
52
52
  end
53
53
  memoize :success?
54
54
 
55
- # Return strategy
55
+ # Return integration
56
56
  #
57
- # @return [Strategy]
57
+ # @return [Integration]
58
58
  #
59
59
  # @api private
60
60
  #
61
- def strategy
62
- config.strategy
61
+ def integration
62
+ config.integration
63
63
  end
64
64
 
65
65
  # Return coverage
@@ -115,13 +115,13 @@ module Mutant
115
115
  # @api private
116
116
  #
117
117
  def run_subjects
118
- strategy = self.strategy
119
- strategy.setup
118
+ integration = self.integration
119
+ integration.setup
120
120
  @subjects = visit_collection(config.subjects)
121
- strategy.teardown
121
+ integration.teardown
122
122
  end
123
123
 
124
- # Run with strategy management
124
+ # Run configuration
125
125
  #
126
126
  # @return [undefined]
127
127
  #