mutant 0.5.17 → 0.5.18

Sign up to get free protection for your applications and to get access to all the features.
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