mutant 0.2.20 → 0.3.0.beta2

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