mutant 0.3.6 → 0.5.0

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 (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