mutant 0.3.6 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -0
  3. data/Changelog.md +13 -0
  4. data/Gemfile +1 -1
  5. data/Guardfile +7 -25
  6. data/LICENSE +1 -1
  7. data/README.md +16 -10
  8. data/config/flay.yml +1 -1
  9. data/config/reek.yml +11 -11
  10. data/config/rubocop.yml +1 -1
  11. data/lib/mutant.rb +3 -10
  12. data/lib/mutant/cli.rb +199 -80
  13. data/lib/mutant/config.rb +3 -3
  14. data/lib/mutant/killer.rb +20 -0
  15. data/lib/mutant/matcher/filter.rb +3 -8
  16. data/lib/mutant/matcher/method/instance.rb +1 -1
  17. data/lib/mutant/matcher/namespace.rb +31 -2
  18. data/lib/mutant/matcher/null.rb +26 -0
  19. data/lib/mutant/mutation.rb +0 -1
  20. data/lib/mutant/reporter/cli/printer.rb +29 -0
  21. data/lib/mutant/reporter/cli/printer/config.rb +16 -116
  22. data/lib/mutant/runner/config.rb +47 -1
  23. data/lib/mutant/strategy.rb +39 -1
  24. data/lib/mutant/version.rb +1 -1
  25. data/lib/mutant/walker.rb +51 -0
  26. data/mutant-rspec.gemspec +24 -0
  27. data/mutant.gemspec +7 -3
  28. data/spec/integration/mutant/rspec_spec.rb +11 -6
  29. data/spec/integration/mutant/zombie_spec.rb +2 -2
  30. data/spec/shared/method_matcher_behavior.rb +6 -6
  31. data/spec/spec_helper.rb +2 -2
  32. data/spec/unit/mutant/cli_new_spec.rb +49 -34
  33. data/spec/unit/mutant/context/scope/root_spec.rb +1 -1
  34. data/spec/unit/mutant/loader/eval_spec.rb +2 -2
  35. data/spec/unit/mutant/matcher/chain_spec.rb +1 -1
  36. data/spec/unit/mutant/matcher/methods/instance_spec.rb +1 -1
  37. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +1 -1
  38. data/spec/unit/mutant/matcher/namespace_spec.rb +1 -1
  39. data/spec/unit/mutant/mutation_spec.rb +1 -1
  40. data/spec/unit/mutant/{killer/rspec_spec.rb → rspec/killer_spec.rb} +2 -1
  41. data/spec/unit/mutant/runner/config_spec.rb +36 -21
  42. data/spec/unit/mutant_spec.rb +7 -9
  43. metadata +25 -22
  44. data/lib/mutant/cli/builder.rb +0 -167
  45. data/lib/mutant/killer/rspec.rb +0 -95
  46. data/lib/mutant/predicate.rb +0 -70
  47. data/lib/mutant/predicate/attribute.rb +0 -68
  48. data/lib/mutant/predicate/blacklist.rb +0 -27
  49. data/lib/mutant/predicate/matcher.rb +0 -38
  50. data/lib/mutant/predicate/whitelist.rb +0 -28
  51. data/lib/mutant/strategy/rspec.rb +0 -76
  52. data/spec/unit/mutant/cli/builder/rspec_spec.rb +0 -38
  53. data/spec/unit/mutant/matcher/filter_spec.rb +0 -19
  54. data/spec/unit/mutant/predicate_spec.rb +0 -135
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f59906eaae74d48bd002bf30178571853d2af117
4
- data.tar.gz: 08efab444be18fa267bdfd7fd7e0b644fc40e2ab
3
+ metadata.gz: e603e77505aa94ac731c26cf64c5b3f85453746a
4
+ data.tar.gz: 44f1fbd18eefabeb1770af343343fa5e0ab2a56c
5
5
  SHA512:
6
- metadata.gz: fa62d1908fc639d8ba4cc713c44374db670d92f8aa5f9b6cf011efcce0d78c98f92fc9c799c0e397887aeb228e926240dfe446d9d6b24ecac3f886a6913b0971
7
- data.tar.gz: 406669d0fa589a75ee96d530dddef31dcafd54b67c16ff5faaea4c6f476f107e392ca666bbbd965c039d64cbc4babe58527b874afdb1718ecf0056bb91884f7d
6
+ metadata.gz: 9a189701a6e9fee5573dfcd7ba638e9bf04219f38738a33a143d61cc6d58c26f0cf3369339b27716f71269b58f45a9f3328c14239431642b0c28d6997f2034fe
7
+ data.tar.gz: 71629135ffe50088a0ea524034df7af56ec43bb9a7cae9ab4ef900fa30877fe2aa5c403f86d62c7cee4607cce28b7ee16cebba5417ea0aab514073f19ea9504a
data/.travis.yml CHANGED
@@ -8,6 +8,7 @@ rvm:
8
8
  matrix:
9
9
  allow_failures:
10
10
  - rvm: rbx
11
+ - rvm: 2.1.0
11
12
  notifications:
12
13
  irc:
13
14
  channels:
data/Changelog.md CHANGED
@@ -1,3 +1,16 @@
1
+ # v0.5.0 2014-02-16
2
+
3
+ Changes:
4
+
5
+ * Add configurable coverage expectation via --coverage (default 100%)
6
+ * rspec integration was moved into a gem 'mutant-rspec'
7
+ * Replace filters implementation with morpher predicates
8
+ * Drop --rspec option use: --use rspec instead.
9
+
10
+ # v0.4.0 2014-02-16
11
+
12
+ Status: Yanked because of broken dependencies.
13
+
1
14
  # v0.3.4 2014-01-11
2
15
 
3
16
  Changes:
data/Gemfile CHANGED
@@ -4,7 +4,7 @@ source 'https://rubygems.org'
4
4
 
5
5
  gem 'mutant', path: '.'
6
6
 
7
- gemspec
7
+ gemspec name: 'mutant'
8
8
 
9
9
  gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
10
10
  eval_gemfile 'Gemfile.devtools'
data/Guardfile CHANGED
@@ -2,33 +2,15 @@
2
2
 
3
3
  guard :bundler do
4
4
  watch('Gemfile')
5
- watch('Gemfile.lock')
6
- watch(%w{.+.gemspec\z})
7
5
  end
8
6
 
9
- guard :rspec, cli: File.read('.rspec').split.push('--fail-fast').join(' '), keep_failed: false do
10
- # Run all specs if configuration is modified
11
- watch('.rspec') { 'spec' }
12
- watch('Guardfile') { 'spec' }
13
- watch('Gemfile.lock') { 'spec' }
14
- watch('spec/spec_helper.rb') { 'spec' }
7
+ guard :rspec, :all_after_pass => false, :all_on_start => false, :cmd => 'bundle exec rspec --fail-fast --seed 0' do
8
+ # run all specs if the spec_helper or supporting files files are modified
9
+ watch('spec/spec_helper.rb') { 'spec/unit' }
10
+ watch(%r{\Aspec/(?:lib|support|shared)/.+\.rb\z}) { 'spec/unit' }
15
11
 
16
- # Run all specs if supporting files files are modified
17
- watch(%r{\Aspec/(?:fixtures|lib|support|shared)/.+\.rb\z}) { 'spec' }
12
+ watch(%r{lib/.*.rb}) { 'spec/unit' }
18
13
 
19
- # Run unit specs if associated lib code is modified
20
- watch(%r{\Alib/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}*"] }
21
- watch(%r{\Alib/(.+)/support/(.+)\.rb\z}) { |m| Dir["spec/unit/#{m[1]}/#{m[2]}*"] }
22
- watch("lib/#{File.basename(File.expand_path('../', __FILE__))}.rb") { 'spec' }
23
-
24
- # Run a spec if it is modified
25
- watch(%r{\Aspec/(?:unit|integration)/.+_spec\.rb\z})
14
+ # run a spec if it is modified
15
+ watch(%r{\Aspec/.+_spec\.rb\z})
26
16
  end
27
-
28
- # Deactivated for now. Somehow it disables the rspec guard.
29
- #
30
- # guard :rubocop, cli: %w[--config config/rubocop.yml] do
31
- # watch(%r{.+\.(?:rb|rake)\z})
32
- # watch(%r{\Aconfig/rubocop\.yml\z}) { |m| File.dirname(m[0]) }
33
- # watch(%r{(?:.+/)?\.rubocop\.yml\z}) { |m| File.dirname(m[0]) }
34
- # end
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2012 Markus Schirp
1
+ Copyright (c) 2012-2014 Markus Schirp
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -12,12 +12,14 @@ or it does not have a speced side effect.
12
12
 
13
13
  A more readable introduction can be found under: http://solnic.eu/2013/01/23/mutation-testing-with-mutant.html
14
14
 
15
- Mutant supports MRI and RBX 1.9 and 2.0, while support for jruby is planned. It should also work under
16
- any ruby engine that supports POSIX-fork(2) semantics.
15
+ Mutant supports MRI and RBX 1.9 and 2.0, while support for jruby is planned.
16
+ It should also work under any ruby engine that supports POSIX-fork(2) semantics.
17
+ Support for MRI 2.1 is unstable, because this MRI release segfaults on basic metaprogramming mutants dependencies do.
17
18
 
18
- Only rspec2 is supported currently. This is subject to change.
19
+ Integrations
20
+ ------------
19
21
 
20
- It is easy to write a mutation killer/strategy for other test/spec frameworks than rspec2.
22
+ Only rspec2 is supported currently.
21
23
 
22
24
  Projects using Mutant
23
25
  ---------------------
@@ -44,10 +46,14 @@ Installation
44
46
 
45
47
  Install the gem `mutant` via your preferred method.
46
48
 
47
- The 0.2 series is stable but has outdated dependencies. The 0.3 series is in beta phase currently.
49
+ ```ruby
50
+ gem install mutant
51
+ ```
52
+
53
+ If you plan to use the rspec integration you'll have to install `mutant-rspec` also.
48
54
 
49
55
  ```ruby
50
- gem install mutant --pre
56
+ gem install mutant-rspec
51
57
  ```
52
58
 
53
59
  Mutations
@@ -86,13 +92,13 @@ Examples
86
92
  ```
87
93
  cd virtus
88
94
  # Run mutant on virtus namespace
89
- mutant --include lib --require virtus --rspec ::Virtus*
95
+ mutant --include lib --require virtus --use rspec ::Virtus*
90
96
  # Run mutant on specific virtus class
91
- mutant --include lib --require virtus --rspec ::Virtus::Attribute
97
+ mutant --include lib --require virtus --use rspec ::Virtus::Attribute
92
98
  # Run mutant on specific virtus class method
93
- mutant --include lib --require virtus --rspec ::Virtus::Attribute.build
99
+ mutant --include lib --require virtus --use rspec ::Virtus::Attribute.build
94
100
  # Run mutant on specific virtus instance method
95
- mutant --include lib --require virtus --rspec ::Virtus::Attribute#type
101
+ mutant --include lib --require virtus --use rspec ::Virtus::Attribute#type
96
102
  ```
97
103
 
98
104
  Presentations:
data/config/flay.yml CHANGED
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 18
3
- total_score: 790
3
+ total_score: 811
data/config/reek.yml CHANGED
@@ -24,14 +24,15 @@ DuplicateMethodCall:
24
24
  FeatureEnvy:
25
25
  enabled: true
26
26
  exclude:
27
- - Mutant::CLI#parse
28
- - Mutant::CLI#add_strategies
29
27
  - Mutant::Matcher::Method::Instance#match?
30
28
  - Mutant::Matcher::Method::Singleton#receiver?
31
29
  - Mutant::Mutation::Evil#success?
32
30
  - Mutant::Mutation::Neutral#success?
33
31
  - Mutant::Reporter::CLI#subject_results
34
- - Mutant::Strategy::Rspec#options
32
+ - Mutant::Rspec::Strategy#options
33
+ # Nature of OptionParser :(
34
+ - Mutant::CLI#add_environmental_options
35
+ - Mutant::CLI#parse
35
36
  IrresponsibleModule:
36
37
  enabled: true
37
38
  exclude: []
@@ -80,14 +81,14 @@ TooManyStatements:
80
81
  enabled: true
81
82
  exclude:
82
83
  - Mutant#self.singleton_subclass_instance
83
- - Mutant::CLI#parse
84
- - Mutant::CLI#add_options
85
- - Mutant::CLI#add_strategies
86
- - Mutant::Killer::Rspec#run
84
+ - Mutant::Rspec::Killer#run
87
85
  - Mutant::Reporter::CLI#colorized_diff
88
86
  - Mutant::Reporter::CLI::Printer::Config::Runner#run
89
87
  - Mutant::Runner#dispatch
90
88
  - Mutant::Zombifier::File#self.find_uncached
89
+ # How mutant does CLI parsing is shit
90
+ - Mutant::CLI#parse
91
+ - Mutant::CLI#initialize
91
92
  max_statements: 6
92
93
  UncommunicativeMethodName:
93
94
  enabled: true
@@ -132,8 +133,7 @@ UtilityFunction:
132
133
  - Mutant::Mutation::Evil#success?
133
134
  - Mutant::Mutation::Neutral#success?
134
135
  - Mutant::NodeHelpers#s
135
- - Mutant::Strategy::Rspec#configuration
136
- - Mutant::Strategy::Rspec#options
137
- - Mutant::Strategy::Rspec#world
138
-
136
+ - Mutant::Rspec::Strategy#configuration
137
+ - Mutant::Rspec::Strategy#options
138
+ - Mutant::Rspec::Strategy#world
139
139
  max_helper_calls: 0
data/config/rubocop.yml CHANGED
@@ -89,7 +89,7 @@ MultilineBlockChain:
89
89
  Enabled: false
90
90
 
91
91
  ClassLength:
92
- Max: 105
92
+ Max: 119
93
93
 
94
94
  # I align private keywords with class body
95
95
  IndentationWidth:
data/lib/mutant.rb CHANGED
@@ -17,10 +17,9 @@ require 'unparser'
17
17
  require 'ice_nine'
18
18
  require 'diff/lcs'
19
19
  require 'diff/lcs/hunk'
20
- require 'rspec'
21
20
  require 'anima'
22
21
  require 'concord'
23
- require 'rspec'
22
+ require 'morpher'
24
23
 
25
24
  # Library namespace
26
25
  module Mutant
@@ -34,11 +33,7 @@ require 'mutant/node_helpers'
34
33
  require 'mutant/singleton_methods'
35
34
  require 'mutant/constants'
36
35
  require 'mutant/random'
37
- require 'mutant/predicate'
38
- require 'mutant/predicate/attribute'
39
- require 'mutant/predicate/whitelist'
40
- require 'mutant/predicate/blacklist'
41
- require 'mutant/predicate/matcher'
36
+ require 'mutant/walker'
42
37
  require 'mutant/mutator'
43
38
  require 'mutant/mutation'
44
39
  require 'mutant/mutation/evil'
@@ -111,13 +106,12 @@ require 'mutant/matcher/methods'
111
106
  require 'mutant/matcher/namespace'
112
107
  require 'mutant/matcher/scope'
113
108
  require 'mutant/matcher/filter'
109
+ require 'mutant/matcher/null'
114
110
  require 'mutant/killer'
115
111
  require 'mutant/killer/static'
116
- require 'mutant/killer/rspec'
117
112
  require 'mutant/killer/forking'
118
113
  require 'mutant/killer/forked'
119
114
  require 'mutant/strategy'
120
- require 'mutant/strategy/rspec'
121
115
  require 'mutant/runner'
122
116
  require 'mutant/runner/config'
123
117
  require 'mutant/runner/subject'
@@ -126,7 +120,6 @@ require 'mutant/cli'
126
120
  require 'mutant/cli/classifier'
127
121
  require 'mutant/cli/classifier/namespace'
128
122
  require 'mutant/cli/classifier/method'
129
- require 'mutant/cli/builder'
130
123
  require 'mutant/color'
131
124
  require 'mutant/differ'
132
125
  require 'mutant/reporter'
data/lib/mutant/cli.rb CHANGED
@@ -6,7 +6,7 @@ module Mutant
6
6
 
7
7
  # Comandline parser
8
8
  class CLI
9
- include Adamantium::Flat, Equalizer.new(:config)
9
+ include Adamantium::Flat, Equalizer.new(:config), NodeHelpers
10
10
 
11
11
  # Error raised when CLI argv is invalid
12
12
  Error = Class.new(RuntimeError)
@@ -32,6 +32,132 @@ module Mutant
32
32
  EXIT_FAILURE
33
33
  end
34
34
 
35
+ # Builder for configuration components
36
+ class Builder
37
+ include NodeHelpers
38
+
39
+ # Initalize object
40
+ #
41
+ # @return [undefined]
42
+ #
43
+ # @api private
44
+ #
45
+ def initialize
46
+ @matchers = []
47
+ @subject_ignores = []
48
+ @subject_selectors = []
49
+ end
50
+
51
+ # Add a subject ignore
52
+ #
53
+ # @param [Matcher]
54
+ #
55
+ # @return [self]
56
+ #
57
+ # @api private
58
+ #
59
+ def add_subject_ignore(matcher)
60
+ @subject_ignores << matcher
61
+ self
62
+ end
63
+
64
+ # Add a subject selector
65
+ #
66
+ # @param [#call] selector
67
+ #
68
+ # @return [self]
69
+ def add_subject_selector(selector)
70
+ @subject_selectors << selector
71
+ self
72
+ end
73
+
74
+ # Add a subject matcher
75
+ #
76
+ # @param [#call] selector
77
+ #
78
+ # @return [self]
79
+ #
80
+ # @api private
81
+ #
82
+ def add_matcher(matcher)
83
+ @matchers << matcher
84
+ self
85
+ end
86
+
87
+ def matcher
88
+ if @matchers.empty?
89
+ raise(Error, 'No patterns given')
90
+ end
91
+
92
+ matcher = Matcher::Chain.build(@matchers)
93
+
94
+ if predicate
95
+ Matcher::Filter.new(matcher, predicate)
96
+ else
97
+ matcher
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ # Return subject selector
104
+ #
105
+ # @return [#call]
106
+ # if selector is present
107
+ #
108
+ # @return [nil]
109
+ # otherwise
110
+ #
111
+ # @api private
112
+ #
113
+ def subject_selector
114
+ if @subject_selectors.any?
115
+ Morpher::Evaluator::Predicate::Or.new(@subject_selectors)
116
+ end
117
+ end
118
+
119
+ # Return predicate
120
+ #
121
+ # @return [#call]
122
+ # if filter is needed
123
+ #
124
+ # @return [nil]
125
+ # othrwise
126
+ #
127
+ # @api private
128
+ #
129
+ def predicate
130
+ if subject_selector && subject_rejector
131
+ Morpher::Evaluator::Predicate::And.new([
132
+ subject_selector,
133
+ Morpher::Evaluator::Predicate::Negation.new(subject_rejector)
134
+ ])
135
+ elsif subject_selector
136
+ subject_selector
137
+ elsif subject_rejector
138
+ Morpher::Evaluator::Predicate::Negation.new(subject_rejector)
139
+ else
140
+ nil
141
+ end
142
+ end
143
+
144
+ # Return subject rejector
145
+ #
146
+ # @return [#call]
147
+ #
148
+ # @api private
149
+ #
150
+ def subject_rejector
151
+ rejectors = @subject_ignores.flat_map(&:to_a).map do |subject|
152
+ Morpher.evaluator(s(:eql, s(:attribute, :identification), s(:static, subject.identification)))
153
+ end
154
+
155
+ if rejectors.any?
156
+ Morpher::Evaluator::Predicate::Or.new(rejectors)
157
+ end
158
+ end
159
+ end
160
+
35
161
  # Initialize objecct
36
162
  #
37
163
  # @param [Array<String>]
@@ -41,10 +167,11 @@ module Mutant
41
167
  # @api private
42
168
  #
43
169
  def initialize(arguments = [])
44
- @filters, @matchers = [], []
170
+ @builder = Builder.new
45
171
  @debug = @fail_fast = @zombie = false
172
+ @expect_coverage = 100.0
173
+ @strategy = Strategy::Null.new
46
174
  @cache = Mutant::Cache.new
47
- @strategy_builder = nil
48
175
  parse(arguments)
49
176
  config # trigger lazyness now
50
177
  end
@@ -60,56 +187,17 @@ module Mutant
60
187
  cache: @cache,
61
188
  zombie: @zombie,
62
189
  debug: @debug,
63
- matcher: matcher,
64
- subject_predicate: @subject_predicate.output,
65
- strategy: @strategy.output,
190
+ matcher: @builder.matcher,
191
+ strategy: @strategy,
66
192
  fail_fast: @fail_fast,
67
- reporter: reporter
193
+ reporter: Reporter::CLI.new($stdout),
194
+ expected_coverage: @expect_coverage
68
195
  )
69
196
  end
70
197
  memoize :config
71
198
 
72
199
  private
73
200
 
74
- # Return reporter
75
- #
76
- # @return [Mutant::Reporter::CLI]
77
- #
78
- # @api private
79
- #
80
- def reporter
81
- Reporter::CLI.new($stdout)
82
- end
83
-
84
- # Return matcher
85
- #
86
- # @return [Mutant::Matcher]
87
- #
88
- # @raise [CLI::Error]
89
- # raises error when matcher is not given
90
- #
91
- # @api private
92
- #
93
- def matcher
94
- if @matchers.empty?
95
- raise(Error, 'No matchers given')
96
- end
97
-
98
- Matcher::Chain.build(@matchers)
99
- end
100
-
101
- # Add mutation filter
102
- #
103
- # @param [Class<Predicate>] klass
104
- #
105
- # @return [undefined]
106
- #
107
- # @api private
108
- #
109
- def add_filter(klass, *arguments)
110
- @filters << klass.new(*arguments)
111
- end
112
-
113
201
  # Parse the command-line options
114
202
  #
115
203
  # @param [Array<String>] arguments
@@ -124,11 +212,12 @@ module Mutant
124
212
  #
125
213
  def parse(arguments)
126
214
  opts = OptionParser.new do |builder|
127
- builder.banner = 'usage: mutant STRATEGY [options] MATCHERS ...'
215
+ builder.banner = 'usage: mutant STRATEGY [options] PATTERN ...'
128
216
  builder.separator('')
129
- add_strategies(builder)
130
217
  add_environmental_options(builder)
131
- add_options(builder)
218
+ add_mutation_options(builder)
219
+ add_filter_options(builder)
220
+ add_debug_options(builder)
132
221
  end
133
222
 
134
223
  patterns =
@@ -152,28 +241,7 @@ module Mutant
152
241
  def parse_matchers(patterns)
153
242
  patterns.each do |pattern|
154
243
  matcher = Classifier.run(@cache, pattern)
155
- @matchers << matcher if matcher
156
- end
157
- end
158
-
159
- # Add strategies
160
- #
161
- # @param [OptionParser] parser
162
- #
163
- # @return [undefined]
164
- #
165
- # @api private
166
- #
167
- def add_strategies(parser)
168
- parser.separator(EMPTY_STRING)
169
- parser.separator('Strategies:')
170
-
171
- {
172
- Builder::Rspec => :@strategy,
173
- Builder::Predicate::Subject => :@subject_predicate,
174
- }.each do |builder, instance_variable_name|
175
- builder = builder.new(@cache, parser)
176
- instance_variable_set(instance_variable_name, builder)
244
+ @builder.add_matcher(matcher)
177
245
  end
178
246
  end
179
247
 
@@ -186,6 +254,8 @@ module Mutant
186
254
  # @api private
187
255
  #
188
256
  def add_environmental_options(opts)
257
+ opts.separator('')
258
+ opts.separator('Environment:')
189
259
  opts.on('--zombie', 'Run mutant zombified') do
190
260
  @zombie = true
191
261
  end.on('-I', '--include DIRECTORY', 'Add DIRECTORY to $LOAD_PATH') do |directory|
@@ -195,25 +265,74 @@ module Mutant
195
265
  end
196
266
  end
197
267
 
268
+ # Use plugin
269
+ #
270
+ # FIXME: For now all plugins are strategies. Later they could be anything that allows "late integration".
271
+ #
272
+ # @param [String] name
273
+ #
274
+ # @return [undefined]
275
+ #
276
+ # @api private
277
+ #
278
+ def use(name)
279
+ require "mutant-#{name}"
280
+ @strategy = Strategy.lookup(name).new
281
+ rescue LoadError
282
+ $stderr.puts("Cannot load plugin: #{name.inspect}")
283
+ raise
284
+ end
285
+
198
286
  # Add options
199
287
  #
200
- # @param [Object] opts
288
+ # @param [OptionParser] opts
201
289
  #
202
290
  # @return [undefined]
203
291
  #
204
292
  # @api private
205
293
  #
206
- def add_options(opts)
207
- opts.separator ''
208
- opts.separator 'Options:'
294
+ def add_mutation_options(opts)
295
+ opts.separator(EMPTY_STRING)
296
+ opts.separator('Options:')
297
+
298
+ opts.on('--score COVERAGE', 'Fail unless COVERAGE is not reached exactly') do |coverage|
299
+ @expected_coverage = Float(coverage)
300
+ end.on('--use STRATEGY', 'Use STRATEGY for killing mutations') do |runner|
301
+ use(runner)
302
+ end
303
+ end
209
304
 
210
- opts.on('--version', 'Print mutants version') do |name|
305
+ # Add filter options
306
+ #
307
+ # @param [OptionParser] opts
308
+ #
309
+ # @return [undefined]
310
+ #
311
+ # @api private
312
+ #
313
+ def add_filter_options(opts)
314
+ opts.on('--ignore-subject PATTERN', 'Ignore subjects that match PATTERN') do |pattern|
315
+ @builder.add_subject_ignore(Classifier.run(@cache, pattern))
316
+ end
317
+ opts.on('--code CODE', 'Scope execution to subjects with CODE') do |code|
318
+ @builder.add_subject_selector(Morpher.evaluator(s(:eql, s(:attribute, :code), s(:static, code))))
319
+ end
320
+ end
321
+
322
+ # Add debug options
323
+ #
324
+ # @param [OptionParser] opts
325
+ #
326
+ # @return [undefined]
327
+ #
328
+ # @api private
329
+ #
330
+ def add_debug_options(opts)
331
+ opts.on('--fail-fast', 'Fail fast') do
332
+ @fail_fast = true
333
+ end.on('--version', 'Print mutants version') do |name|
211
334
  puts("mutant-#{Mutant::VERSION}")
212
335
  Kernel.exit(0)
213
- end.on('--code FILTER', 'Adds a code filter') do |filter|
214
- add_filter(Predicate::Attribute, :code, filter)
215
- end.on('--fail-fast', 'Fail fast') do
216
- @fail_fast = true
217
336
  end.on('-d', '--debug', 'Enable debugging output') do
218
337
  @debug = true
219
338
  end.on_tail('-h', '--help', 'Show this message') do