mutant 0.2.20 → 0.3.0.beta2

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 (201) hide show
  1. checksums.yaml +7 -0
  2. data/.travis.yml +10 -11
  3. data/Changelog.md +93 -38
  4. data/Gemfile +3 -1
  5. data/Gemfile.devtools +16 -20
  6. data/Guardfile +1 -1
  7. data/README.md +36 -16
  8. data/Rakefile +21 -2
  9. data/TODO +11 -7
  10. data/bin/mutant +4 -0
  11. data/bin/zombie +4 -0
  12. data/config/devtools.yml +2 -0
  13. data/config/flay.yml +2 -2
  14. data/config/flog.yml +1 -1
  15. data/config/{site.reek → reek.yml} +94 -70
  16. data/lib/mutant/cli/classifier/method.rb +100 -0
  17. data/lib/mutant/cli/classifier/namespace.rb +47 -0
  18. data/lib/mutant/cli/classifier/scope.rb +35 -0
  19. data/lib/mutant/cli/classifier.rb +141 -0
  20. data/lib/mutant/cli.rb +115 -162
  21. data/lib/mutant/color.rb +2 -2
  22. data/lib/mutant/config.rb +27 -0
  23. data/lib/mutant/constants.rb +32 -17
  24. data/lib/mutant/context/scope.rb +33 -51
  25. data/lib/mutant/context.rb +8 -19
  26. data/lib/mutant/differ.rb +5 -5
  27. data/lib/mutant/helper.rb +2 -17
  28. data/lib/mutant/killer/forked.rb +44 -0
  29. data/lib/mutant/killer/forking.rb +3 -57
  30. data/lib/mutant/killer/rspec.rb +16 -20
  31. data/lib/mutant/killer/static.rb +6 -7
  32. data/lib/mutant/killer.rb +48 -74
  33. data/lib/mutant/loader.rb +6 -6
  34. data/lib/mutant/matcher/chain.rb +4 -25
  35. data/lib/mutant/matcher/method/instance.rb +14 -24
  36. data/lib/mutant/matcher/method/singleton.rb +35 -46
  37. data/lib/mutant/matcher/method.rb +95 -83
  38. data/lib/mutant/matcher/{scope_methods.rb → methods.rb} +53 -76
  39. data/lib/mutant/matcher/namespace.rb +71 -0
  40. data/lib/mutant/matcher/scope.rb +34 -0
  41. data/lib/mutant/matcher.rb +24 -34
  42. data/lib/mutant/mutation/evil.rb +35 -0
  43. data/lib/mutant/mutation/filter/code.rb +7 -28
  44. data/lib/mutant/mutation/filter/regexp.rb +6 -18
  45. data/lib/mutant/mutation/filter/whitelist.rb +5 -4
  46. data/lib/mutant/mutation/filter.rb +10 -9
  47. data/lib/mutant/mutation/neutral.rb +35 -0
  48. data/lib/mutant/mutation.rb +21 -61
  49. data/lib/mutant/mutator/node/argument.rb +88 -0
  50. data/lib/mutant/mutator/node/arguments.rb +52 -0
  51. data/lib/mutant/mutator/node/assignment.rb +34 -38
  52. data/lib/mutant/mutator/node/begin.rb +33 -0
  53. data/lib/mutant/mutator/node/block.rb +14 -14
  54. data/lib/mutant/mutator/node/case.rb +59 -0
  55. data/lib/mutant/mutator/node/define.rb +26 -22
  56. data/lib/mutant/mutator/node/if.rb +31 -71
  57. data/lib/mutant/mutator/node/literal/array.rb +25 -9
  58. data/lib/mutant/mutator/node/literal/boolean.rb +13 -30
  59. data/lib/mutant/mutator/node/literal/dynamic.rb +6 -5
  60. data/lib/mutant/mutator/node/literal/fixnum.rb +18 -7
  61. data/lib/mutant/mutator/node/literal/float.rb +15 -8
  62. data/lib/mutant/mutator/node/literal/hash.rb +33 -52
  63. data/lib/mutant/mutator/node/literal/nil.rb +8 -7
  64. data/lib/mutant/mutator/node/literal/range.rb +25 -50
  65. data/lib/mutant/mutator/node/literal/regex.rb +15 -23
  66. data/lib/mutant/mutator/node/literal/string.rb +7 -6
  67. data/lib/mutant/mutator/node/literal/symbol.rb +7 -6
  68. data/lib/mutant/mutator/node/literal.rb +4 -46
  69. data/lib/mutant/mutator/node/mlhs.rb +27 -0
  70. data/lib/mutant/mutator/node/noop.rb +18 -43
  71. data/lib/mutant/mutator/node/return.rb +8 -8
  72. data/lib/mutant/mutator/node/send/binary.rb +31 -0
  73. data/lib/mutant/mutator/node/send.rb +106 -72
  74. data/lib/mutant/mutator/node/super.rb +15 -20
  75. data/lib/mutant/mutator/node/when.rb +32 -7
  76. data/lib/mutant/mutator/node/while.rb +9 -7
  77. data/lib/mutant/mutator/node.rb +116 -66
  78. data/lib/mutant/mutator/registry.rb +14 -11
  79. data/lib/mutant/mutator/util/array.rb +9 -9
  80. data/lib/mutant/mutator/util/symbol.rb +6 -20
  81. data/lib/mutant/mutator/util.rb +6 -3
  82. data/lib/mutant/mutator.rb +12 -28
  83. data/lib/mutant/node_helpers.rb +28 -0
  84. data/lib/mutant/random.rb +3 -2
  85. data/lib/mutant/reporter/cli/printer/config.rb +174 -0
  86. data/lib/mutant/reporter/cli/printer/killer.rb +42 -0
  87. data/lib/mutant/reporter/cli/printer/mutation.rb +55 -0
  88. data/lib/mutant/reporter/cli/printer/subject.rb +147 -0
  89. data/lib/mutant/reporter/cli/printer.rb +165 -0
  90. data/lib/mutant/reporter/cli.rb +9 -277
  91. data/lib/mutant/reporter/null.rb +6 -30
  92. data/lib/mutant/reporter.rb +6 -73
  93. data/lib/mutant/runner/config.rb +82 -0
  94. data/lib/mutant/runner/mutation.rb +58 -0
  95. data/lib/mutant/runner/subject.rb +81 -0
  96. data/lib/mutant/runner.rb +42 -92
  97. data/lib/mutant/singleton_methods.rb +2 -2
  98. data/lib/mutant/strategy/method_expansion.rb +51 -0
  99. data/lib/mutant/strategy/rspec/dm2/lookup/method.rb +142 -0
  100. data/lib/mutant/strategy/rspec/dm2/lookup.rb +61 -0
  101. data/lib/mutant/strategy/rspec/dm2.rb +22 -0
  102. data/lib/mutant/strategy/rspec.rb +20 -22
  103. data/lib/mutant/strategy/static.rb +18 -0
  104. data/lib/mutant/strategy.rb +15 -50
  105. data/lib/mutant/subject/method.rb +100 -0
  106. data/lib/mutant/subject.rb +18 -49
  107. data/lib/mutant/support/method_object.rb +4 -2
  108. data/lib/mutant.rb +40 -35
  109. data/mutant.gemspec +9 -8
  110. data/spec/integration/mutant/rspec_killer_spec.rb +3 -3
  111. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +9 -0
  112. data/spec/integration/mutant/zombie_spec.rb +1 -1
  113. data/spec/shared/method_matcher_behavior.rb +35 -0
  114. data/spec/shared/mutator_behavior.rb +63 -32
  115. data/spec/spec_helper.rb +13 -3
  116. data/spec/support/ice_nine_config.rb +8 -0
  117. data/spec/support/rspec.rb +1 -1
  118. data/spec/support/zombie.rb +1 -1
  119. data/spec/unit/mutant/cli/class_methods/new_spec.rb +42 -28
  120. data/spec/unit/mutant/cli/class_methods/run_spec.rb +15 -13
  121. data/spec/unit/mutant/cli/classifier/class_methods/build_spec.rb +44 -0
  122. data/spec/unit/mutant/context/scope/root_spec.rb +4 -4
  123. data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +6 -5
  124. data/spec/unit/mutant/killer/success_predicate_spec.rb +28 -0
  125. data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +1 -1
  126. data/spec/unit/mutant/matcher/chain/each_spec.rb +1 -1
  127. data/spec/unit/mutant/matcher/chain/matchers_spec.rb +1 -1
  128. data/spec/unit/mutant/matcher/method/instance/each_spec.rb +112 -0
  129. data/spec/unit/mutant/matcher/method/singleton/each_spec.rb +93 -0
  130. data/spec/unit/mutant/matcher/methods/instance/each_spec.rb +59 -0
  131. data/spec/unit/mutant/matcher/methods/singleton/each_spec.rb +53 -0
  132. data/spec/unit/mutant/matcher/namespace/each_spec.rb +37 -0
  133. data/spec/unit/mutant/mutator/node/begin/mutation_spec.rb +33 -0
  134. data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +42 -14
  135. data/spec/unit/mutant/mutator/node/case/mutation_spec.rb +319 -0
  136. data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +31 -27
  137. data/spec/unit/mutant/mutator/node/if/mutation_spec.rb +75 -0
  138. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -1
  139. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +2 -2
  140. data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +1 -3
  141. data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +1 -9
  142. data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +6 -2
  143. data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +111 -108
  144. data/spec/unit/mutant/mutator/node/super/mutation_spec.rb +0 -33
  145. data/spec/unit/mutant/mutator/node/while/mutation_spec.rb +2 -2
  146. data/spec/unit/mutant/runner/config/subjects_spec.rb +38 -0
  147. data/spec/unit/mutant/runner/config/success_predicate_spec.rb +53 -0
  148. data/spec/unit/mutant/runner/failed_predicte_spec.rb +33 -0
  149. data/spec/unit/mutant/runner/mutation/killer_spec.rb +39 -0
  150. data/spec/unit/mutant/runner/subject/success_predicate_spec.rb +49 -0
  151. data/spec/unit/mutant/strategy/method_expansion/class_methods/run_spec.rb +49 -0
  152. data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/instance/spec_files_spec.rb +52 -0
  153. data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/singleton/spec_files_spec.rb +42 -0
  154. data/spec/unit/mutant/subject/context_spec.rb +6 -3
  155. data/spec/unit/mutant/subject/each_spec.rb +11 -8
  156. data/spec/unit/mutant/subject/node_spec.rb +6 -2
  157. data/test_app/spec/shared/method_filter_parse_behavior.rb +0 -2
  158. data/test_app/spec/shared/method_match_behavior.rb +1 -1
  159. data/test_app/spec/spec_helper.rb +4 -2
  160. metadata +101 -109
  161. data/config/roodi.yml +0 -26
  162. data/lib/mutant/matcher/method/classifier.rb +0 -141
  163. data/lib/mutant/matcher/object_space.rb +0 -114
  164. data/lib/mutant/mutator/node/actual_arguments.rb +0 -25
  165. data/lib/mutant/mutator/node/default_arguments.rb +0 -25
  166. data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +0 -33
  167. data/lib/mutant/mutator/node/formal_arguments_19/pattern_argument_expansion.rb +0 -35
  168. data/lib/mutant/mutator/node/formal_arguments_19/require_defaults.rb +0 -37
  169. data/lib/mutant/mutator/node/formal_arguments_19.rb +0 -41
  170. data/lib/mutant/mutator/node/iter_19.rb +0 -27
  171. data/lib/mutant/mutator/node/literal/empty_array.rb +0 -26
  172. data/lib/mutant/mutator/node/pattern_arguments.rb +0 -41
  173. data/lib/mutant/mutator/node/pattern_variable.rb +0 -23
  174. data/lib/mutant/mutator/node/receiver_case.rb +0 -122
  175. data/lib/mutant/mutator/node/send/binary_operator_method.rb +0 -61
  176. data/lib/mutant/mutator/node/send/with_arguments.rb +0 -81
  177. data/lib/mutant/reporter/stats.rb +0 -120
  178. data/lib/mutant/strategy/rspec/example_lookup.rb +0 -163
  179. data/spec/integration/mutant/method_matching_spec.rb +0 -269
  180. data/spec/shared/method_match_behavior.rb +0 -39
  181. data/spec/unit/mutant/killer/fail_ques_spec.rb +0 -39
  182. data/spec/unit/mutant/matcher/class_methods/from_string_spec.rb +0 -49
  183. data/spec/unit/mutant/matcher/class_methods/parse_spec.rb +0 -12
  184. data/spec/unit/mutant/matcher/method/class_methods/parse_spec.rb +0 -21
  185. data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +0 -52
  186. data/spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb +0 -24
  187. data/spec/unit/mutant/matcher/object_space/each_spec.rb +0 -31
  188. data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +0 -60
  189. data/spec/unit/mutant/mutator/node/receiver_case/mutation_spec.rb +0 -27
  190. data/spec/unit/mutant/strategy/rspec/example_lookup/spec_file_spec.rb +0 -236
  191. data/spec/unit/mutant/subject/class_methods/new_spec.rb +0 -13
  192. data/tasks/metrics/ci.rake +0 -7
  193. data/tasks/metrics/flay.rake +0 -41
  194. data/tasks/metrics/flog.rake +0 -43
  195. data/tasks/metrics/heckle.rake +0 -216
  196. data/tasks/metrics/metric_fu.rake +0 -31
  197. data/tasks/metrics/reek.rake +0 -15
  198. data/tasks/metrics/roodi.rake +0 -15
  199. data/tasks/metrics/yardstick.rake +0 -23
  200. data/tasks/spec.rake +0 -45
  201. data/tasks/yard.rake +0 -9
data/lib/mutant/cli.rb CHANGED
@@ -1,9 +1,12 @@
1
+ require 'optparse'
2
+
1
3
  module Mutant
4
+
2
5
  # Comandline parser
3
6
  class CLI
4
- include Adamantium::Flat, Equalizer.new(:matcher, :filter, :strategy, :reporter)
7
+ include Adamantium::Flat, Equalizer.new(:config)
5
8
 
6
- # Error raised when CLI argv is inalid
9
+ # Error raised when CLI argv is invalid
7
10
  Error = Class.new(RuntimeError)
8
11
 
9
12
  EXIT_FAILURE = 1
@@ -18,31 +21,49 @@ module Mutant
18
21
  #
19
22
  # @api private
20
23
  #
21
- def self.run(*arguments)
22
- error = Runner.run(new(*arguments)).fail?
23
- error ? EXIT_FAILURE : EXIT_SUCCESS
24
+ def self.run(arguments)
25
+ config = new(arguments).config
26
+ runner = Runner::Config.run(config)
27
+ runner.success? ? EXIT_SUCCESS : EXIT_FAILURE
24
28
  rescue Error => exception
25
29
  $stderr.puts(exception.message)
26
30
  EXIT_FAILURE
27
31
  end
28
32
 
29
- # Return matcher
33
+ # Initialize objecct
30
34
  #
31
- # @return [Mutant::Matcher]
35
+ # @param [Array<String>]
32
36
  #
33
- # @raise [CLI::Error]
34
- # raises error when matcher is not given
37
+ # @return [undefined]
35
38
  #
36
39
  # @api private
37
40
  #
38
- def matcher
39
- if @matchers.empty?
40
- raise Error, 'No matchers given'
41
- end
41
+ def initialize(arguments=[])
42
+ @filters, @matchers = [], []
43
+
44
+ parse(arguments)
45
+ strategy
46
+ matcher
47
+ end
42
48
 
43
- Mutant::Matcher::Chain.build(@matchers)
49
+ # Return config
50
+ #
51
+ # @return [Config]
52
+ #
53
+ # @api private
54
+ #
55
+ def config
56
+ Config.new(
57
+ :debug => debug?,
58
+ :matcher => matcher,
59
+ :filter => filter,
60
+ :strategy => strategy,
61
+ :reporter => reporter
62
+ )
44
63
  end
45
- memoize :matcher
64
+ memoize :config
65
+
66
+ private
46
67
 
47
68
  # Test for running in debug mode
48
69
  #
@@ -80,8 +101,7 @@ module Mutant
80
101
  # @api private
81
102
  #
82
103
  def strategy
83
- @strategy || raise(Error, 'no strategy was set!')
84
- @strategy.new(self)
104
+ @strategy or raise(Error, 'No strategy was set!')
85
105
  end
86
106
  memoize :strategy
87
107
 
@@ -92,217 +112,150 @@ module Mutant
92
112
  # @api private
93
113
  #
94
114
  def reporter
95
- Mutant::Reporter::CLI.new(self)
115
+ Reporter::CLI.new($stdout)
96
116
  end
97
117
  memoize :reporter
98
118
 
99
- private
100
-
101
- OPTIONS = {
102
- '--code' => [:add_filter, Mutation::Filter::Code ],
103
- '-I' => [:add_load_path ],
104
- '--include' => [:add_load_path ],
105
- '-r' => [:require_library ],
106
- '--require' => [:require_library ],
107
- '--debug' => [:set_debug ],
108
- '-d' => [:set_debug ],
109
- '--rspec-unit' => [:set_strategy, Strategy::Rspec::Unit ],
110
- '--rspec-full' => [:set_strategy, Strategy::Rspec::Full ],
111
- '--rspec-dm2' => [:set_strategy, Strategy::Rspec::DM2 ],
112
- '--static-fail' => [:set_strategy, Strategy::Static::Fail ],
113
- '--static-success' => [:set_strategy, Strategy::Static::Success ]
114
- }.freeze
115
-
116
- OPTION_PATTERN = %r(\A-(?:-)?[a-zA-Z0-9\-]+\z).freeze
117
-
118
- # Initialize CLI
119
+ # Return matcher
119
120
  #
120
- # @param [Array<String>] arguments
121
+ # @return [Mutant::Matcher]
121
122
  #
122
- # @return [undefined]
123
+ # @raise [CLI::Error]
124
+ # raises error when matcher is not given
123
125
  #
124
126
  # @api private
125
127
  #
126
- def initialize(arguments)
127
- @filters, @matchers = [], []
128
-
129
- @arguments, @index = arguments, 0
130
-
131
- while @index < @arguments.length
132
- dispatch
128
+ def matcher
129
+ if @matchers.empty?
130
+ raise Error, 'No matchers given'
133
131
  end
134
132
 
135
- strategy
136
- matcher
133
+ Matcher::Chain.build(@matchers)
137
134
  end
135
+ memoize :matcher
138
136
 
139
- # Return option for argument with index
137
+ # Add mutation filter
138
+ #
139
+ # @param [Class<Mutant::Filter>] klass
140
140
  #
141
- # @param [Fixnum] index
141
+ # @param [String] filter
142
142
  #
143
- # @return [String]
143
+ # @return [undefined]
144
144
  #
145
145
  # @api private
146
146
  #
147
- def option(index)
148
- @arguments.fetch(index+1)
147
+ def add_filter(klass,filter)
148
+ @filters << klass.new(filter)
149
149
  end
150
150
 
151
- # Return current argument
152
- #
153
- # @return [String]
151
+ # Set debug mode
154
152
  #
155
153
  # @api private
156
154
  #
157
- def current_argument
158
- @arguments.fetch(@index)
155
+ # @return [undefined]
156
+ #
157
+ def set_debug
158
+ @debug = true
159
159
  end
160
160
 
161
- # Return current option value
162
- #
163
- # @return [String]
161
+ # Set strategy
164
162
  #
165
- # @raise [CLI::Error]
166
- # raises error when option is missing
163
+ # @param [Strategy] strategy
167
164
  #
168
165
  # @api private
169
166
  #
170
- def current_option_value
171
- @arguments.fetch(@index+1)
172
- rescue IndexError
173
- raise Error, "#{current_argument.inspect} is missing an argument"
174
- end
175
-
176
- # Process current argument
177
- #
178
167
  # @return [undefined]
179
168
  #
180
- # @api private
181
- #
182
- def dispatch
183
- if OPTION_PATTERN =~ current_argument
184
- dispatch_option
185
- else
186
- dispatch_matcher
187
- end
169
+ def set_strategy(strategy)
170
+ @strategy = strategy
188
171
  end
189
172
 
190
- # Move processed argument by amount
191
- #
192
- # @param [Fixnum] amount
193
- # the amount of arguments to be consumed
173
+ # Parse the command-line options
194
174
  #
195
- # @return [undefined]
175
+ # @param [Array<String>] arguments
176
+ # Command-line options and arguments to be parsed.
196
177
  #
197
- # @api private
178
+ # @raise [Error]
179
+ # An error occurred while parsing the options.
198
180
  #
199
- def consume(amount)
200
- @index += amount
201
- end
202
-
203
- # Process matcher argument
204
- #
205
181
  # @return [undefined]
206
182
  #
207
183
  # @api private
208
184
  #
209
- def dispatch_matcher
210
- argument = current_argument
211
- matcher = Mutant::Matcher.from_string(argument)
185
+ def parse(arguments)
186
+ opts = OptionParser.new do |opts|
187
+ opts.banner = 'usage: mutant STRATEGY [options] MATCHERS ...'
188
+ opts.separator ''
189
+ opts.separator 'Strategies:'
212
190
 
213
- unless matcher
214
- raise Error, "Invalid matcher syntax: #{argument.inspect}"
191
+ add_strategies(opts)
192
+ add_options(opts)
215
193
  end
216
194
 
217
- @matchers << matcher
195
+ matchers =
196
+ begin
197
+ opts.parse!(arguments)
198
+ rescue OptionParser::ParseError => error
199
+ raise(Error, error.message, error.backtrace)
200
+ end
218
201
 
219
- consume(1)
202
+ parse_matchers(matchers)
220
203
  end
221
204
 
222
- # Process option argument
205
+ # Parse matchers
223
206
  #
224
- # @return [Undefined]
225
- #
226
- # @api private
227
- #
228
- def dispatch_option
229
- argument = current_argument
230
- arguments = *OPTIONS.fetch(argument) do
231
- raise Error, "Unknown option: #{argument.inspect}"
232
- end
233
- send(*arguments)
234
- end
235
-
236
- # Add mutation filter
237
- #
238
- # @param [Class<Mutant::Filter>] klass
207
+ # @param [Enumerable<String>] patterns
239
208
  #
240
209
  # @return [undefined]
241
210
  #
242
211
  # @api private
243
212
  #
244
- def add_filter(klass)
245
- @filters << klass.new(current_option_value)
246
- consume(2)
213
+ def parse_matchers(patterns)
214
+ patterns.each do |pattern|
215
+ matcher = Classifier.build(pattern)
216
+ @matchers << matcher if matcher
217
+ end
247
218
  end
248
219
 
249
- # Add load path
220
+ # Add strategies
250
221
  #
251
- # @api private
222
+ # @param [Object]
252
223
  #
253
224
  # @return [undefined]
254
225
  #
255
- def add_load_path
256
- $LOAD_PATH << current_option_value
257
- consume(2)
258
- end
259
-
260
- # Enable rspec
261
- #
262
226
  # @api private
263
227
  #
264
- # @return [self]
265
- #
266
- # @api private
267
- #
268
- def enable_rspec
269
- consume(1)
270
- @rspec = true
228
+ def add_strategies(opts)
229
+ opts.on('--rspec-unit', 'executes all specs under ./spec/unit') do
230
+ set_strategy Strategy::Rspec::Unit
231
+ end.on('--rspec-full', 'executes all specs under ./spec') do
232
+ set_strategy Strategy::Rspec::Full
233
+ end.on('--rspec-dm2', 'executes spec/unit/namespace/class/method_spec.rb') do
234
+ set_strategy Strategy::Rspec::DM2
235
+ end
271
236
  end
272
237
 
273
- # Set debug mode
238
+ # Add options
274
239
  #
275
- # @api private
240
+ # @param [Object]
276
241
  #
277
242
  # @return [undefined]
278
243
  #
279
- def set_debug
280
- consume(1)
281
- @debug = true
282
- end
283
-
284
- # Set strategy
285
- #
286
- # @param [Strategy] strategy
287
- #
288
244
  # @api private
289
245
  #
290
- # @return [undefined]
291
- #
292
- def set_strategy(strategy)
293
- consume(1)
294
- @strategy = strategy
246
+ def add_options(opts)
247
+ opts.separator ''
248
+ opts.separator 'Options:'
249
+
250
+ opts.on('--code FILTER', 'Adds a code filter') do |filter|
251
+ add_filter Mutation::Filter::Code, filter
252
+ end.on('-d','--debug', 'Enable debugging output') do
253
+ set_debug
254
+ end.on_tail('-h', '--help', 'Show this message') do
255
+ puts opts
256
+ exit
257
+ end
295
258
  end
296
259
 
297
- # Require library
298
- #
299
- # @api private
300
- #
301
- # @return [undefined]
302
- #
303
- def require_library
304
- require(current_option_value)
305
- consume(2)
306
- end
307
- end
308
- end
260
+ end # CLI
261
+ end # Mutant
data/lib/mutant/color.rb CHANGED
@@ -57,5 +57,5 @@ module Mutant
57
57
  RED = Color.new(31)
58
58
  GREEN = Color.new(32)
59
59
  BLUE = Color.new(34)
60
- end
61
- end
60
+ end # Color
61
+ end # Mutant
@@ -0,0 +1,27 @@
1
+ module Mutant
2
+ # The configuration of a mutator run
3
+ class Config
4
+ include Adamantium::Flat, Anima.new(
5
+ :debug, :strategy, :matcher, :filter, :reporter
6
+ )
7
+
8
+ # Enumerate subjects
9
+ #
10
+ # @api private
11
+ #
12
+ # @return [self]
13
+ # if block given
14
+ #
15
+ # @return [Enumerator<Subject>]
16
+ # otherwise
17
+ #
18
+ # @api private
19
+ #
20
+ def subjects(&block)
21
+ return to_enum(__method__) unless block_given?
22
+ matcher.each(&block)
23
+ self
24
+ end
25
+
26
+ end # Config
27
+ end # Mutant
@@ -1,16 +1,12 @@
1
1
  module Mutant
2
2
 
3
- # The list of ruby kewords from http://ruby-doc.org/docs/keywords/1.9/
4
- KEYWORDS = %w(
5
- BEGIN END __ENCODING__ __END__ __FILE__
6
- __LINE__ alias and begin break case class
7
- def define do else elsif end ensure false
8
- for if in module next nil not or redo
9
- rescue retry return self super then true
10
- undef unless until when while yield
11
- ).map(&:to_sym).to_set.freeze
3
+ METHOD_POSTFIX_EXPANSIONS = {
4
+ '?' => '_predicate',
5
+ '=' => '_writer',
6
+ '!' => '_bang'
7
+ }.freeze
12
8
 
13
- BINARY_METHOD_OPERATOR_EXPANSIONS = {
9
+ OPERATOR_EXPANSIONS = {
14
10
  :<=> => :spaceship_operator,
15
11
  :=== => :case_equality_operator,
16
12
  :[]= => :element_writer,
@@ -33,17 +29,36 @@ module Mutant
33
29
  :< => :less_than_operator,
34
30
  :> => :greater_than_operator,
35
31
  :+ => :addition_operator,
36
- :- => :substraction_operator
37
- }.freeze
38
-
39
- UNARY_METHOD_OPERATOR_EXPANSIONS = {
32
+ :- => :substraction_operator,
40
33
  :~@ => :unary_match_operator,
41
34
  :+@ => :unary_addition_operator,
42
35
  :-@ => :unary_substraction_operator,
43
36
  :'!' => :negation_operator
44
37
  }.freeze
45
38
 
46
- BINARY_METHOD_OPERATORS = BINARY_METHOD_OPERATOR_EXPANSIONS.keys.to_set.freeze
39
+ INDEX_OPERATORS = [ :[], :[]= ].freeze
40
+
41
+ UNARY_METHOD_OPERATORS = [
42
+ :~@, :+@, :-@, :'!'
43
+ ].freeze
44
+
45
+ BINARY_METHOD_OPERATORS = (OPERATOR_EXPANSIONS.keys - (INDEX_OPERATORS + UNARY_METHOD_OPERATORS)).to_set.freeze
47
46
 
48
- OPERATOR_EXPANSIONS = BINARY_METHOD_OPERATOR_EXPANSIONS.merge(UNARY_METHOD_OPERATOR_EXPANSIONS).freeze
49
- end
47
+ # Hopefully all types parser does generate
48
+ NODE_TYPES = [
49
+ :lvasgn, :ivasgn, :cvasgn, :gvasgn,
50
+ :casgn, :masgn, :mlhs, :break, :rescue,
51
+ :ensure, :resbody, :begin, :retry, :arg_expr,
52
+ :args, :blockarg, :optarg, :kwrestarg, :kwoptarg,
53
+ :kwarg, :restarg, :arg, :block_pass, :or, :and,
54
+ :next, :undef, :if, :module, :cbase, :block, :send,
55
+ :zsuper, :super, :empty, :alias, :for, :redo,
56
+ :return, :splat, :not, :defined?, :op_asgn, :self,
57
+ :true, :false, :nil, :dstr, :dsym, :regexp,
58
+ :regopt, :int, :str, :float, :sym, :pair, :hash, :array,
59
+ :xstr, :def, :defs, :case, :when, :ivar, :lvar, :cvar, :gvar,
60
+ :back_ref, :const, :nth_ref, :class, :sclass, :yield,
61
+ :match_with_lvasgn, :match_current_line, :irange, :erange,
62
+ :or_asgn
63
+ ].to_set.freeze
64
+ end # Mutant,
@@ -3,10 +3,11 @@ module Mutant
3
3
  # Scope context for mutation (Class or Module)
4
4
  class Scope < self
5
5
  include Adamantium::Flat, Equalizer.new(:scope, :source_path)
6
+ extend NodeHelpers
6
7
 
7
8
  # Return AST wrapping mutated node
8
9
  #
9
- # @return [Rubinius::AST::Script]
10
+ # @return [Parser::AST::Node]
10
11
  #
11
12
  # @api private
12
13
  #
@@ -16,26 +17,36 @@ module Mutant
16
17
  end
17
18
  end
18
19
 
20
+ # Return identification
21
+ #
22
+ # @return [String]
23
+ #
24
+ # @ai private
25
+ #
26
+ def identification
27
+ scope.name
28
+ end
29
+
19
30
  # Wrap node into ast node
20
31
  #
21
- # @param [Class, Module] scope
22
- # @param [Rubinius::AST::Node] node
32
+ # @param [Class, Module] scope
33
+ # @param [Parser::AST::Node] node
23
34
  #
24
- # @return [Rubinius::AST::Class]
35
+ # @return [Parser::AST::Class]
25
36
  # if scope is of kind Class
26
37
  #
27
- # @return [Rubinius::AST::Module]
38
+ # @return [Parser::AST::Module]
28
39
  # if scope is of kind module
29
40
  #
30
41
  # @api private
31
42
  #
32
43
  def self.wrap(scope, node)
33
- name = scope.name.split('::').last.to_sym
44
+ name = s(:const, nil, scope.name.split('::').last.to_sym)
34
45
  case scope
35
46
  when ::Class
36
- ::Rubinius::AST::Class.new(0, name, nil, node)
47
+ s(:class, name, nil, node)
37
48
  when ::Module
38
- ::Rubinius::AST::Module.new(0, name, node)
49
+ s(:module, name, node)
39
50
  else
40
51
  raise "Cannot wrap scope: #{scope.inspect}"
41
52
  end
@@ -66,6 +77,16 @@ module Mutant
66
77
  name_nesting.last
67
78
  end
68
79
 
80
+ # Return name
81
+ #
82
+ # @return [String]
83
+ #
84
+ # @api private
85
+ #
86
+ def name
87
+ scope.name
88
+ end
89
+
69
90
  # Return scope wrapped by context
70
91
  #
71
92
  # @return [::Module|::Class]
@@ -88,46 +109,6 @@ module Mutant
88
109
  @scope = scope
89
110
  end
90
111
 
91
- # Return scope AST class
92
- #
93
- # @return [Rubinius::AST::Node]
94
- #
95
- # @api private
96
- #
97
- def scope_class
98
- self.class::SCOPE_CLASS
99
- end
100
-
101
- # Return keyword
102
- #
103
- # @return [Rubinius::AST::Node]
104
- #
105
- # @api private
106
- #
107
- def keyword
108
- self.class::KEYWORD
109
- end
110
-
111
- # Return new root ast
112
- #
113
- # @return [Rubinius::AST::Node]
114
- #
115
- # @api private
116
- #
117
- def root_ast
118
- "#{keyword} #{qualified_name}; end".to_ast
119
- end
120
-
121
- # Return qualified name of scope
122
- #
123
- # @return [String]
124
- #
125
- # @api private
126
- #
127
- def qualified_name
128
- scope.name
129
- end
130
-
131
112
  # Return nesting of names of scope
132
113
  #
133
114
  # @return [Array<String>]
@@ -138,6 +119,7 @@ module Mutant
138
119
  scope.name.split('::')
139
120
  end
140
121
  memoize :name_nesting
141
- end
142
- end
143
- end
122
+
123
+ end # Scope
124
+ end # Context
125
+ end # Mutant
@@ -1,36 +1,25 @@
1
1
  module Mutant
2
2
  # An abstract context where mutations can be appied to.
3
3
  class Context
4
- include Adamantium::Flat, AbstractType
4
+ include Adamantium::Flat, AbstractType, Concord::Public.new(:source_path)
5
5
 
6
6
  # Return root ast node
7
7
  #
8
- # @return [Rubinis::AST::Script]
8
+ # @param [Parser::AST::Node] node
9
+ #
10
+ # @return [Parser::AST::Node]
9
11
  #
10
12
  # @api private
11
13
  #
12
14
  abstract_method :root
13
15
 
14
- # Return source path
16
+ # Return identification
15
17
  #
16
18
  # @return [String]
17
19
  #
18
20
  # @api private
19
21
  #
20
- attr_reader :source_path
21
-
22
- private
22
+ abstract_method :identification
23
23
 
24
- # Initialize context
25
- #
26
- # @param [String] source_path
27
- #
28
- # @return [undefined]
29
- #
30
- # @api private
31
- #
32
- def initialize(source_path)
33
- @source_path = source_path
34
- end
35
- end
36
- end
24
+ end # Context
25
+ end # Mutant
data/lib/mutant/differ.rb CHANGED
@@ -3,7 +3,7 @@ module Mutant
3
3
  class Differ
4
4
  include Adamantium::Flat
5
5
 
6
- # Return source diff
6
+ # Return source diff
7
7
  #
8
8
  # @return [String]
9
9
  #
@@ -20,7 +20,7 @@ module Mutant
20
20
  end
21
21
  memoize :diff
22
22
 
23
- # Return colorized source diff
23
+ # Return colorized source diff
24
24
  #
25
25
  # @return [String]
26
26
  #
@@ -40,7 +40,7 @@ module Mutant
40
40
 
41
41
  # Initialize differ object
42
42
  #
43
- # @param [String] old
43
+ # @param [String] old
44
44
  # @param [String] new
45
45
  #
46
46
  # @return [undefined]
@@ -107,6 +107,6 @@ module Mutant
107
107
  Color::NONE
108
108
  end.format(line)
109
109
  end
110
- end
111
- end
112
110
 
111
+ end # Differ
112
+ end # Mutant