mutant 0.5.17 → 0.5.18

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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +6 -0
  3. data/Rakefile +13 -0
  4. data/config/flay.yml +1 -1
  5. data/config/reek.yml +8 -1
  6. data/lib/mutant.rb +18 -3
  7. data/lib/mutant/cli.rb +6 -3
  8. data/lib/mutant/constants.rb +3 -0
  9. data/lib/mutant/expression.rb +110 -0
  10. data/lib/mutant/expression/method.rb +92 -0
  11. data/lib/mutant/expression/namespace.rb +90 -0
  12. data/lib/mutant/matcher/namespace.rb +3 -4
  13. data/lib/mutant/meta.rb +31 -0
  14. data/lib/mutant/meta/example.rb +152 -0
  15. data/lib/mutant/meta/example/dsl.rb +105 -0
  16. data/lib/mutant/mutator/node.rb +6 -6
  17. data/lib/mutant/mutator/node/arguments.rb +1 -1
  18. data/lib/mutant/mutator/node/begin.rb +1 -1
  19. data/lib/mutant/mutator/node/const.rb +1 -1
  20. data/lib/mutant/mutator/node/if.rb +6 -6
  21. data/lib/mutant/mutator/node/literal/array.rb +2 -2
  22. data/lib/mutant/mutator/node/literal/hash.rb +2 -2
  23. data/lib/mutant/mutator/node/literal/range.rb +3 -3
  24. data/lib/mutant/mutator/node/literal/regex.rb +2 -2
  25. data/lib/mutant/mutator/node/literal/symbol.rb +1 -1
  26. data/lib/mutant/mutator/node/op_asgn.rb +1 -3
  27. data/lib/mutant/mutator/node/or_asgn.rb +31 -0
  28. data/lib/mutant/mutator/node/send.rb +1 -1
  29. data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -1
  30. data/lib/mutant/reporter/cli/report/mutation.rb +11 -1
  31. data/lib/mutant/strategy.rb +1 -1
  32. data/lib/mutant/version.rb +1 -1
  33. data/meta/and.rb +12 -0
  34. data/meta/and_asgn.rb +12 -0
  35. data/meta/array.rb +30 -0
  36. data/meta/begin.rb +15 -0
  37. data/meta/binary.rb +12 -0
  38. data/meta/block.rb +55 -0
  39. data/meta/block_pass.rb +8 -0
  40. data/meta/blockarg.rb +10 -0
  41. data/meta/boolean.rb +15 -0
  42. data/meta/break.rb +11 -0
  43. data/meta/case.rb +303 -0
  44. data/meta/casgn.rb +9 -0
  45. data/meta/cbase.rb +8 -0
  46. data/meta/const.rb +9 -0
  47. data/meta/cvar.rb +7 -0
  48. data/meta/cvasgn.rb +10 -0
  49. data/meta/define.rb +118 -0
  50. data/meta/defined.rb +7 -0
  51. data/meta/dstr.rb +10 -0
  52. data/meta/dsym.rb +11 -0
  53. data/meta/ensure.rb +9 -0
  54. data/meta/fixnum.rb +19 -0
  55. data/meta/float.rb +38 -0
  56. data/meta/gvar.rb +7 -0
  57. data/meta/gvasgn.rb +10 -0
  58. data/meta/hash.rb +25 -0
  59. data/meta/if.rb +57 -0
  60. data/meta/ivasgn.rb +10 -0
  61. data/meta/kwbegin.rb +9 -0
  62. data/meta/lvar.rb +14 -0
  63. data/meta/lvasgn.rb +10 -0
  64. data/meta/masgn.rb +7 -0
  65. data/meta/match_current_line.rb +14 -0
  66. data/meta/next.rb +11 -0
  67. data/meta/nil.rb +5 -0
  68. data/meta/nthref.rb +14 -0
  69. data/meta/op_assgn.rb +15 -0
  70. data/meta/or_asgn.rb +22 -0
  71. data/meta/range.rb +41 -0
  72. data/meta/redo.rb +5 -0
  73. data/meta/regex.rb +20 -0
  74. data/meta/rescue.rb +38 -0
  75. data/meta/restarg.rb +11 -0
  76. data/meta/return.rb +15 -0
  77. data/meta/self.rb +7 -0
  78. data/meta/send.rb +240 -0
  79. data/meta/string.rb +7 -0
  80. data/meta/super.rb +26 -0
  81. data/meta/symbol.rb +8 -0
  82. data/meta/unless.rb +15 -0
  83. data/meta/while.rb +24 -0
  84. data/meta/yield.rb +10 -0
  85. data/mutant.gemspec +1 -0
  86. data/spec/integration/mutant/corpus_spec.rb +29 -25
  87. data/spec/spec_helper.rb +2 -0
  88. data/spec/support/mutation_verifier.rb +1 -0
  89. data/spec/unit/mutant/cli_new_spec.rb +6 -6
  90. data/spec/unit/mutant/expression/method_spec.rb +50 -0
  91. data/spec/unit/mutant/expression/namespace/flat_spec.rb +32 -0
  92. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +37 -0
  93. data/spec/unit/mutant/matcher/namespace_spec.rb +2 -2
  94. data/spec/unit/mutant/mutation_spec.rb +1 -1
  95. data/spec/unit/mutant/mutator/node_spec.rb +14 -0
  96. metadata +123 -139
  97. data/lib/mutant/cli/classifier.rb +0 -139
  98. data/lib/mutant/cli/classifier/method.rb +0 -105
  99. data/lib/mutant/cli/classifier/namespace.rb +0 -49
  100. data/spec/unit/mutant/cli/classifier/method_spec.rb +0 -77
  101. data/spec/unit/mutant/cli/classifier/namespace/flat_spec.rb +0 -58
  102. data/spec/unit/mutant/cli/classifier/namespace/recursive_spec.rb +0 -58
  103. data/spec/unit/mutant/cli/classifier_spec.rb +0 -59
  104. data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +0 -19
  105. data/spec/unit/mutant/mutator/node/begin_spec.rb +0 -32
  106. data/spec/unit/mutant/mutator/node/binary_spec.rb +0 -41
  107. data/spec/unit/mutant/mutator/node/block_pass_spec.rb +0 -15
  108. data/spec/unit/mutant/mutator/node/block_spec.rb +0 -83
  109. data/spec/unit/mutant/mutator/node/blockarg_spec.rb +0 -17
  110. data/spec/unit/mutant/mutator/node/case_spec.rb +0 -329
  111. data/spec/unit/mutant/mutator/node/cbase_spec.rb +0 -15
  112. data/spec/unit/mutant/mutator/node/conditional_loop_spec.rb +0 -58
  113. data/spec/unit/mutant/mutator/node/const_spec.rb +0 -16
  114. data/spec/unit/mutant/mutator/node/define_spec.rb +0 -171
  115. data/spec/unit/mutant/mutator/node/defined_spec.rb +0 -14
  116. data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -17
  117. data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -18
  118. data/spec/unit/mutant/mutator/node/ensure_spec.rb +0 -16
  119. data/spec/unit/mutant/mutator/node/if_spec.rb +0 -77
  120. data/spec/unit/mutant/mutator/node/kwbegin_spec.rb +0 -16
  121. data/spec/unit/mutant/mutator/node/literal/array_spec.rb +0 -47
  122. data/spec/unit/mutant/mutator/node/literal/boolean_spec.rb +0 -25
  123. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +0 -13
  124. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -53
  125. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +0 -33
  126. data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +0 -10
  127. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -56
  128. data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +0 -36
  129. data/spec/unit/mutant/mutator/node/literal/string_spec.rb +0 -15
  130. data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +0 -15
  131. data/spec/unit/mutant/mutator/node/loop_ctrl_spec.rb +0 -37
  132. data/spec/unit/mutant/mutator/node/masgn_spec.rb +0 -14
  133. data/spec/unit/mutant/mutator/node/match_current_line_spec.rb +0 -21
  134. data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +0 -78
  135. data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +0 -16
  136. data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +0 -61
  137. data/spec/unit/mutant/mutator/node/nthref_spec.rb +0 -19
  138. data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -22
  139. data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +0 -19
  140. data/spec/unit/mutant/mutator/node/redo_spec.rb +0 -10
  141. data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -63
  142. data/spec/unit/mutant/mutator/node/restarg_spec.rb +0 -18
  143. data/spec/unit/mutant/mutator/node/return_spec.rb +0 -31
  144. data/spec/unit/mutant/mutator/node/send_spec.rb +0 -382
  145. data/spec/unit/mutant/mutator/node/super_spec.rb +0 -46
  146. data/spec/unit/mutant/mutator/node/yield_spec.rb +0 -17
@@ -36,7 +36,7 @@ module Mutant
36
36
  # @api private
37
37
  #
38
38
  def pattern
39
- /\A#{Regexp.escape(namespace.name)}(?:::)?/
39
+ /\A#{Regexp.escape(namespace)}(?:::)?/
40
40
  end
41
41
  memoize :pattern
42
42
 
@@ -87,12 +87,11 @@ It raised an error: #{exception.inspect} fix your lib!
87
87
  #
88
88
  def emit_scope(scope)
89
89
  name = self.class.scope_name(scope)
90
- # FIXME: Fix nokogiri to return a string here
91
90
  unless name.nil? or name.kind_of?(String)
92
91
  $stderr.puts <<-MESSAGE
93
92
  WARNING:
94
- #{scope.class}#name did not return a string or nil.
95
- Fix your lib!
93
+ #{scope.class}#name from: #{scope.inspect} did not return a String or nil.
94
+ Fix your lib to support normal ruby semantics!
96
95
  MESSAGE
97
96
  return
98
97
  end
@@ -0,0 +1,31 @@
1
+ module Mutant
2
+ # Namespace for mutant metadata
3
+ module Meta
4
+
5
+ require 'mutant/meta/example'
6
+ require 'mutant/meta/example/dsl'
7
+
8
+ # Mutation example
9
+ class Example
10
+
11
+ ALL = []
12
+
13
+ # Add example
14
+ #
15
+ # @return [undefined]
16
+ #
17
+ # @api private
18
+ #
19
+ def self.add(&block)
20
+ ALL << DSL.run(block)
21
+ end
22
+
23
+ Pathname.glob(Pathname.new(__FILE__).parent.parent.parent.join('meta', '**/*.rb'))
24
+ .sort
25
+ .each(&method(:require))
26
+ ALL.freeze
27
+
28
+ end # Example
29
+
30
+ end # Meta
31
+ end # Mutant
@@ -0,0 +1,152 @@
1
+ # encoding: UTF-8
2
+
3
+ module Mutant
4
+ module Meta
5
+ class Example
6
+ include Adamantium, Concord::Public.new(:node, :mutations)
7
+
8
+ # Return a verification instance
9
+ #
10
+ # @return [Verification]
11
+ #
12
+ # @api private
13
+ #
14
+ def verification
15
+ Verification.new(self, generated)
16
+ end
17
+
18
+ # Return generated mutations
19
+ #
20
+ # @return [Emumerable<Parser::AST::Node>]
21
+ #
22
+ # @api private
23
+ #
24
+ def generated
25
+ Mutant::Mutator.each(node).to_a
26
+ end
27
+ memoize :generated
28
+
29
+ # Example verification
30
+ class Verification
31
+ include Adamantium::Flat, Concord.new(:example, :generated)
32
+
33
+ # Test if mutation was verified successfully
34
+ #
35
+ # @return [Boolean]
36
+ #
37
+ # @api private
38
+ #
39
+ def success?
40
+ unparser.success? && missing.empty? && unexpected.empty?
41
+ end
42
+
43
+ # Return error report
44
+ #
45
+ # @return [String]
46
+ #
47
+ # @api private
48
+ #
49
+ def error_report
50
+ unless unparser.success?
51
+ return unparser.report
52
+ end
53
+ mutation_report
54
+ end
55
+
56
+ private
57
+
58
+ # Return unexpected mutationso
59
+ #
60
+ # @return [Array<Parser::AST::Node>]
61
+ #
62
+ # @api private
63
+ #
64
+ def unexpected
65
+ generated - example.mutations
66
+ end
67
+ memoize :unexpected
68
+
69
+ # Return mutation report
70
+ #
71
+ # @return [String]
72
+ #
73
+ # @api private
74
+ #
75
+ def mutation_report
76
+ original_node = example.node
77
+ [
78
+ 'Original-AST:',
79
+ original_node.inspect,
80
+ 'Original-Source:',
81
+ Unparser.unparse(original_node),
82
+ *missing_report,
83
+ *unexpected_report
84
+ ].join("\n======\n")
85
+ end
86
+
87
+ # Return missing report
88
+ #
89
+ # @return [Array, nil]
90
+ #
91
+ # @api private
92
+ #
93
+ def missing_report
94
+ if missing.any?
95
+ ['Missing mutations:', missing.map(&method(:format_mutation)).join("\n-----\n")]
96
+ end
97
+ end
98
+
99
+ # Return unexpected report
100
+ #
101
+ # @return [Array, nil]
102
+ #
103
+ # @api private
104
+ #
105
+ def unexpected_report
106
+ if unexpected.any?
107
+ [
108
+ 'Unexpected mutations:',
109
+ unexpected.map(&method(:format_mutation)).join("\n-----\n")
110
+ ]
111
+ end
112
+ end
113
+
114
+ # Format mutation
115
+ #
116
+ # @return [String]
117
+ #
118
+ # @api private
119
+ #
120
+ def format_mutation(node)
121
+ [
122
+ node.inspect,
123
+ Unparser.unparse(node)
124
+ ].join("\n")
125
+ end
126
+
127
+ # Return missing mutationso
128
+ #
129
+ # @return [Array<Parser::AST::Node>]
130
+ #
131
+ # @api private
132
+ #
133
+ def missing
134
+ example.mutations - generated
135
+ end
136
+ memoize :missing
137
+
138
+ # Return unparser verifier
139
+ #
140
+ # @return [Unparser::CLI::Source]
141
+ #
142
+ # @api private
143
+ #
144
+ def unparser
145
+ Unparser::CLI::Source::Node.new(Unparser::Preprocessor.run(example.node))
146
+ end
147
+ memoize :unparser
148
+
149
+ end # Verification
150
+ end # Example
151
+ end # Meta
152
+ end # Mutant
@@ -0,0 +1,105 @@
1
+ module Mutant
2
+ module Meta
3
+ class Example
4
+
5
+ # Example DSL
6
+ class DSL
7
+ include NodeHelpers
8
+
9
+ # Run DSL on block
10
+ #
11
+ # @return [Example]
12
+ #
13
+ # @api private
14
+ #
15
+ def self.run(block)
16
+ instance = new
17
+ instance.instance_eval(&block)
18
+ instance.example
19
+ end
20
+
21
+ # Initialize DSL context
22
+ #
23
+ # @return [undefined]
24
+ #
25
+ # @api private
26
+ #
27
+ def initialize
28
+ @source = nil
29
+ @expected = []
30
+ end
31
+
32
+ # Return example
33
+ #
34
+ # @return [Example]
35
+ #
36
+ # @raise [RuntimeError]
37
+ # in case example cannot be build
38
+ #
39
+ # @api private
40
+ #
41
+ def example
42
+ raise 'source not defined' unless @source
43
+ Example.new(@source, @expected)
44
+ end
45
+
46
+ private
47
+
48
+ # Set original source
49
+ #
50
+ # @param [String,Parser::AST::Node] input
51
+ #
52
+ # @return [self]
53
+ #
54
+ def source(input)
55
+ raise 'source already defined' if @source
56
+ @source = node(input)
57
+
58
+ self
59
+ end
60
+
61
+ # Add expected mutation
62
+ #
63
+ # @param [String,Parser::AST::Node] input
64
+ #
65
+ # @return [self]
66
+ #
67
+ def mutation(input)
68
+ node = node(input)
69
+ if @expected.include?(node)
70
+ raise "Node for input: #{input.inspect} is already expected"
71
+ end
72
+ @expected << node
73
+
74
+ self
75
+ end
76
+
77
+ # Helper method to coerce input to node
78
+ #
79
+ # @param [String,Parser::AST::Node] input
80
+ #
81
+ # @return [Parser::AST::Node]
82
+ #
83
+ # @raise [RuntimeError]
84
+ # in case input cannot be coerced
85
+ #
86
+ # @api private
87
+ #
88
+ def node(input)
89
+ node =
90
+ case input
91
+ when String
92
+ Parser::CurrentRuby.parse(input)
93
+ when Parser::AST::Node
94
+ input
95
+ else
96
+ raise "Cannot coerce to node: #{source.inspect}"
97
+ end
98
+
99
+ Unparser::Preprocessor.run(node)
100
+ end
101
+
102
+ end # DSL
103
+ end # Example
104
+ end # Meta
105
+ end # Mutant
@@ -96,7 +96,7 @@ module Mutant
96
96
  #
97
97
  def emit_children_mutations
98
98
  Mutator::Util::Array.each(children, self) do |children|
99
- emit_self(*children)
99
+ emit_type(*children)
100
100
  end
101
101
  end
102
102
 
@@ -136,7 +136,7 @@ module Mutant
136
136
  def delete_child(index)
137
137
  dup_children = children.dup
138
138
  dup_children.delete_at(index)
139
- emit_self(*dup_children)
139
+ emit_type(*dup_children)
140
140
  end
141
141
 
142
142
  # Emit updated child
@@ -151,7 +151,7 @@ module Mutant
151
151
  def emit_child_update(index, node)
152
152
  new_children = children.dup
153
153
  new_children[index] = node
154
- emit_self(*new_children)
154
+ emit_type(*new_children)
155
155
  end
156
156
 
157
157
  # Emit a new AST node with same class as wrapped node
@@ -162,7 +162,7 @@ module Mutant
162
162
  #
163
163
  # @api private
164
164
  #
165
- def emit_self(*children)
165
+ def emit_type(*children)
166
166
  emit(new_self(*children))
167
167
  end
168
168
 
@@ -196,7 +196,7 @@ module Mutant
196
196
  #
197
197
  def emit_values(values)
198
198
  values.each do |value|
199
- emit_self(value)
199
+ emit_type(value)
200
200
  end
201
201
  end
202
202
 
@@ -221,7 +221,7 @@ module Mutant
221
221
  # @api private
222
222
  #
223
223
  def asgn_left?
224
- OP_ASSIGN.include?(parent_type) && parent.left.equal?(node)
224
+ OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
225
225
  end
226
226
 
227
227
  end # Node
@@ -32,7 +32,7 @@ module Mutant
32
32
  dup_children = children.dup
33
33
  dup_children.delete_at(index)
34
34
  dup_children.insert(index, *child.children)
35
- emit_self(*dup_children)
35
+ emit_type(*dup_children)
36
36
  end
37
37
  end
38
38
 
@@ -41,7 +41,7 @@ module Mutant
41
41
  when 1
42
42
  emit(children.first)
43
43
  else
44
- emit_self(*children)
44
+ emit_type(*children)
45
45
  end
46
46
  end
47
47
 
@@ -19,7 +19,7 @@ module Mutant
19
19
  #
20
20
  def dispatch
21
21
  emit_nil unless parent_type == :const
22
- emit_self(nil, *children.drop(1))
22
+ emit_type(nil, *children.drop(1))
23
23
  children.each_with_index do |child, index|
24
24
  mutate_child(index) if child.kind_of?(Parser::AST::Node)
25
25
  end
@@ -33,9 +33,9 @@ module Mutant
33
33
  #
34
34
  def mutate_condition
35
35
  emit_condition_mutations
36
- emit_self(n_not(condition), if_branch, else_branch) unless condition.type == :match_current_line
37
- emit_self(N_TRUE, if_branch, else_branch)
38
- emit_self(N_FALSE, if_branch, else_branch)
36
+ emit_type(n_not(condition), if_branch, else_branch) unless condition.type == :match_current_line
37
+ emit_type(N_TRUE, if_branch, else_branch)
38
+ emit_type(N_FALSE, if_branch, else_branch)
39
39
  end
40
40
 
41
41
  # Emit if branch mutations
@@ -45,10 +45,10 @@ module Mutant
45
45
  # @api private
46
46
  #
47
47
  def mutate_if_branch
48
- emit_self(condition, else_branch, nil) if else_branch
48
+ emit_type(condition, else_branch, nil) if else_branch
49
49
  if if_branch
50
50
  emit_if_branch_mutations
51
- emit_self(condition, if_branch, nil)
51
+ emit_type(condition, if_branch, nil)
52
52
  end
53
53
  end
54
54
 
@@ -61,7 +61,7 @@ module Mutant
61
61
  def mutate_else_branch
62
62
  if else_branch
63
63
  emit_else_branch_mutations
64
- emit_self(condition, nil, else_branch)
64
+ emit_type(condition, nil, else_branch)
65
65
  end
66
66
  end
67
67
 
@@ -19,7 +19,7 @@ module Mutant
19
19
  #
20
20
  def dispatch
21
21
  emit_nil
22
- emit_self
22
+ emit_type
23
23
  mutate_body
24
24
  if children.one?
25
25
  emit(children.first)
@@ -36,7 +36,7 @@ module Mutant
36
36
  children.each_index do |index|
37
37
  dup_children = children.dup
38
38
  dup_children.delete_at(index)
39
- emit_self(*dup_children)
39
+ emit_type(*dup_children)
40
40
  mutate_child(index)
41
41
  end
42
42
  end