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.
- checksums.yaml +7 -0
- data/.travis.yml +10 -11
- data/Changelog.md +93 -38
- data/Gemfile +3 -1
- data/Gemfile.devtools +16 -20
- data/Guardfile +1 -1
- data/README.md +36 -16
- data/Rakefile +21 -2
- data/TODO +11 -7
- data/bin/mutant +4 -0
- data/bin/zombie +4 -0
- data/config/devtools.yml +2 -0
- data/config/flay.yml +2 -2
- data/config/flog.yml +1 -1
- data/config/{site.reek → reek.yml} +94 -70
- data/lib/mutant/cli/classifier/method.rb +100 -0
- data/lib/mutant/cli/classifier/namespace.rb +47 -0
- data/lib/mutant/cli/classifier/scope.rb +35 -0
- data/lib/mutant/cli/classifier.rb +141 -0
- data/lib/mutant/cli.rb +115 -162
- data/lib/mutant/color.rb +2 -2
- data/lib/mutant/config.rb +27 -0
- data/lib/mutant/constants.rb +32 -17
- data/lib/mutant/context/scope.rb +33 -51
- data/lib/mutant/context.rb +8 -19
- data/lib/mutant/differ.rb +5 -5
- data/lib/mutant/helper.rb +2 -17
- data/lib/mutant/killer/forked.rb +44 -0
- data/lib/mutant/killer/forking.rb +3 -57
- data/lib/mutant/killer/rspec.rb +16 -20
- data/lib/mutant/killer/static.rb +6 -7
- data/lib/mutant/killer.rb +48 -74
- data/lib/mutant/loader.rb +6 -6
- data/lib/mutant/matcher/chain.rb +4 -25
- data/lib/mutant/matcher/method/instance.rb +14 -24
- data/lib/mutant/matcher/method/singleton.rb +35 -46
- data/lib/mutant/matcher/method.rb +95 -83
- data/lib/mutant/matcher/{scope_methods.rb → methods.rb} +53 -76
- data/lib/mutant/matcher/namespace.rb +71 -0
- data/lib/mutant/matcher/scope.rb +34 -0
- data/lib/mutant/matcher.rb +24 -34
- data/lib/mutant/mutation/evil.rb +35 -0
- data/lib/mutant/mutation/filter/code.rb +7 -28
- data/lib/mutant/mutation/filter/regexp.rb +6 -18
- data/lib/mutant/mutation/filter/whitelist.rb +5 -4
- data/lib/mutant/mutation/filter.rb +10 -9
- data/lib/mutant/mutation/neutral.rb +35 -0
- data/lib/mutant/mutation.rb +21 -61
- data/lib/mutant/mutator/node/argument.rb +88 -0
- data/lib/mutant/mutator/node/arguments.rb +52 -0
- data/lib/mutant/mutator/node/assignment.rb +34 -38
- data/lib/mutant/mutator/node/begin.rb +33 -0
- data/lib/mutant/mutator/node/block.rb +14 -14
- data/lib/mutant/mutator/node/case.rb +59 -0
- data/lib/mutant/mutator/node/define.rb +26 -22
- data/lib/mutant/mutator/node/if.rb +31 -71
- data/lib/mutant/mutator/node/literal/array.rb +25 -9
- data/lib/mutant/mutator/node/literal/boolean.rb +13 -30
- data/lib/mutant/mutator/node/literal/dynamic.rb +6 -5
- data/lib/mutant/mutator/node/literal/fixnum.rb +18 -7
- data/lib/mutant/mutator/node/literal/float.rb +15 -8
- data/lib/mutant/mutator/node/literal/hash.rb +33 -52
- data/lib/mutant/mutator/node/literal/nil.rb +8 -7
- data/lib/mutant/mutator/node/literal/range.rb +25 -50
- data/lib/mutant/mutator/node/literal/regex.rb +15 -23
- data/lib/mutant/mutator/node/literal/string.rb +7 -6
- data/lib/mutant/mutator/node/literal/symbol.rb +7 -6
- data/lib/mutant/mutator/node/literal.rb +4 -46
- data/lib/mutant/mutator/node/mlhs.rb +27 -0
- data/lib/mutant/mutator/node/noop.rb +18 -43
- data/lib/mutant/mutator/node/return.rb +8 -8
- data/lib/mutant/mutator/node/send/binary.rb +31 -0
- data/lib/mutant/mutator/node/send.rb +106 -72
- data/lib/mutant/mutator/node/super.rb +15 -20
- data/lib/mutant/mutator/node/when.rb +32 -7
- data/lib/mutant/mutator/node/while.rb +9 -7
- data/lib/mutant/mutator/node.rb +116 -66
- data/lib/mutant/mutator/registry.rb +14 -11
- data/lib/mutant/mutator/util/array.rb +9 -9
- data/lib/mutant/mutator/util/symbol.rb +6 -20
- data/lib/mutant/mutator/util.rb +6 -3
- data/lib/mutant/mutator.rb +12 -28
- data/lib/mutant/node_helpers.rb +28 -0
- data/lib/mutant/random.rb +3 -2
- data/lib/mutant/reporter/cli/printer/config.rb +174 -0
- data/lib/mutant/reporter/cli/printer/killer.rb +42 -0
- data/lib/mutant/reporter/cli/printer/mutation.rb +55 -0
- data/lib/mutant/reporter/cli/printer/subject.rb +147 -0
- data/lib/mutant/reporter/cli/printer.rb +165 -0
- data/lib/mutant/reporter/cli.rb +9 -277
- data/lib/mutant/reporter/null.rb +6 -30
- data/lib/mutant/reporter.rb +6 -73
- data/lib/mutant/runner/config.rb +82 -0
- data/lib/mutant/runner/mutation.rb +58 -0
- data/lib/mutant/runner/subject.rb +81 -0
- data/lib/mutant/runner.rb +42 -92
- data/lib/mutant/singleton_methods.rb +2 -2
- data/lib/mutant/strategy/method_expansion.rb +51 -0
- data/lib/mutant/strategy/rspec/dm2/lookup/method.rb +142 -0
- data/lib/mutant/strategy/rspec/dm2/lookup.rb +61 -0
- data/lib/mutant/strategy/rspec/dm2.rb +22 -0
- data/lib/mutant/strategy/rspec.rb +20 -22
- data/lib/mutant/strategy/static.rb +18 -0
- data/lib/mutant/strategy.rb +15 -50
- data/lib/mutant/subject/method.rb +100 -0
- data/lib/mutant/subject.rb +18 -49
- data/lib/mutant/support/method_object.rb +4 -2
- data/lib/mutant.rb +40 -35
- data/mutant.gemspec +9 -8
- data/spec/integration/mutant/rspec_killer_spec.rb +3 -3
- data/spec/integration/mutant/test_mutator_handles_types_spec.rb +9 -0
- data/spec/integration/mutant/zombie_spec.rb +1 -1
- data/spec/shared/method_matcher_behavior.rb +35 -0
- data/spec/shared/mutator_behavior.rb +63 -32
- data/spec/spec_helper.rb +13 -3
- data/spec/support/ice_nine_config.rb +8 -0
- data/spec/support/rspec.rb +1 -1
- data/spec/support/zombie.rb +1 -1
- data/spec/unit/mutant/cli/class_methods/new_spec.rb +42 -28
- data/spec/unit/mutant/cli/class_methods/run_spec.rb +15 -13
- data/spec/unit/mutant/cli/classifier/class_methods/build_spec.rb +44 -0
- data/spec/unit/mutant/context/scope/root_spec.rb +4 -4
- data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +6 -5
- data/spec/unit/mutant/killer/success_predicate_spec.rb +28 -0
- data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +1 -1
- data/spec/unit/mutant/matcher/chain/each_spec.rb +1 -1
- data/spec/unit/mutant/matcher/chain/matchers_spec.rb +1 -1
- data/spec/unit/mutant/matcher/method/instance/each_spec.rb +112 -0
- data/spec/unit/mutant/matcher/method/singleton/each_spec.rb +93 -0
- data/spec/unit/mutant/matcher/methods/instance/each_spec.rb +59 -0
- data/spec/unit/mutant/matcher/methods/singleton/each_spec.rb +53 -0
- data/spec/unit/mutant/matcher/namespace/each_spec.rb +37 -0
- data/spec/unit/mutant/mutator/node/begin/mutation_spec.rb +33 -0
- data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +42 -14
- data/spec/unit/mutant/mutator/node/case/mutation_spec.rb +319 -0
- data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +31 -27
- data/spec/unit/mutant/mutator/node/if/mutation_spec.rb +75 -0
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -1
- data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +2 -2
- data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +1 -3
- data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +1 -9
- data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +6 -2
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +111 -108
- data/spec/unit/mutant/mutator/node/super/mutation_spec.rb +0 -33
- data/spec/unit/mutant/mutator/node/while/mutation_spec.rb +2 -2
- data/spec/unit/mutant/runner/config/subjects_spec.rb +38 -0
- data/spec/unit/mutant/runner/config/success_predicate_spec.rb +53 -0
- data/spec/unit/mutant/runner/failed_predicte_spec.rb +33 -0
- data/spec/unit/mutant/runner/mutation/killer_spec.rb +39 -0
- data/spec/unit/mutant/runner/subject/success_predicate_spec.rb +49 -0
- data/spec/unit/mutant/strategy/method_expansion/class_methods/run_spec.rb +49 -0
- data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/instance/spec_files_spec.rb +52 -0
- data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/singleton/spec_files_spec.rb +42 -0
- data/spec/unit/mutant/subject/context_spec.rb +6 -3
- data/spec/unit/mutant/subject/each_spec.rb +11 -8
- data/spec/unit/mutant/subject/node_spec.rb +6 -2
- data/test_app/spec/shared/method_filter_parse_behavior.rb +0 -2
- data/test_app/spec/shared/method_match_behavior.rb +1 -1
- data/test_app/spec/spec_helper.rb +4 -2
- metadata +101 -109
- data/config/roodi.yml +0 -26
- data/lib/mutant/matcher/method/classifier.rb +0 -141
- data/lib/mutant/matcher/object_space.rb +0 -114
- data/lib/mutant/mutator/node/actual_arguments.rb +0 -25
- data/lib/mutant/mutator/node/default_arguments.rb +0 -25
- data/lib/mutant/mutator/node/formal_arguments_19/default_mutations.rb +0 -33
- data/lib/mutant/mutator/node/formal_arguments_19/pattern_argument_expansion.rb +0 -35
- data/lib/mutant/mutator/node/formal_arguments_19/require_defaults.rb +0 -37
- data/lib/mutant/mutator/node/formal_arguments_19.rb +0 -41
- data/lib/mutant/mutator/node/iter_19.rb +0 -27
- data/lib/mutant/mutator/node/literal/empty_array.rb +0 -26
- data/lib/mutant/mutator/node/pattern_arguments.rb +0 -41
- data/lib/mutant/mutator/node/pattern_variable.rb +0 -23
- data/lib/mutant/mutator/node/receiver_case.rb +0 -122
- data/lib/mutant/mutator/node/send/binary_operator_method.rb +0 -61
- data/lib/mutant/mutator/node/send/with_arguments.rb +0 -81
- data/lib/mutant/reporter/stats.rb +0 -120
- data/lib/mutant/strategy/rspec/example_lookup.rb +0 -163
- data/spec/integration/mutant/method_matching_spec.rb +0 -269
- data/spec/shared/method_match_behavior.rb +0 -39
- data/spec/unit/mutant/killer/fail_ques_spec.rb +0 -39
- data/spec/unit/mutant/matcher/class_methods/from_string_spec.rb +0 -49
- data/spec/unit/mutant/matcher/class_methods/parse_spec.rb +0 -12
- data/spec/unit/mutant/matcher/method/class_methods/parse_spec.rb +0 -21
- data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +0 -52
- data/spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb +0 -24
- data/spec/unit/mutant/matcher/object_space/each_spec.rb +0 -31
- data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +0 -60
- data/spec/unit/mutant/mutator/node/receiver_case/mutation_spec.rb +0 -27
- data/spec/unit/mutant/strategy/rspec/example_lookup/spec_file_spec.rb +0 -236
- data/spec/unit/mutant/subject/class_methods/new_spec.rb +0 -13
- data/tasks/metrics/ci.rake +0 -7
- data/tasks/metrics/flay.rake +0 -41
- data/tasks/metrics/flog.rake +0 -43
- data/tasks/metrics/heckle.rake +0 -216
- data/tasks/metrics/metric_fu.rake +0 -31
- data/tasks/metrics/reek.rake +0 -15
- data/tasks/metrics/roodi.rake +0 -15
- data/tasks/metrics/yardstick.rake +0 -23
- data/tasks/spec.rake +0 -45
- 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(:
|
7
|
+
include Adamantium::Flat, Equalizer.new(:config)
|
5
8
|
|
6
|
-
# Error raised when CLI argv is
|
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(
|
22
|
-
|
23
|
-
|
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
|
-
#
|
33
|
+
# Initialize objecct
|
30
34
|
#
|
31
|
-
# @
|
35
|
+
# @param [Array<String>]
|
32
36
|
#
|
33
|
-
# @
|
34
|
-
# raises error when matcher is not given
|
37
|
+
# @return [undefined]
|
35
38
|
#
|
36
39
|
# @api private
|
37
40
|
#
|
38
|
-
def
|
39
|
-
|
40
|
-
|
41
|
-
|
41
|
+
def initialize(arguments=[])
|
42
|
+
@filters, @matchers = [], []
|
43
|
+
|
44
|
+
parse(arguments)
|
45
|
+
strategy
|
46
|
+
matcher
|
47
|
+
end
|
42
48
|
|
43
|
-
|
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 :
|
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
|
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
|
-
|
115
|
+
Reporter::CLI.new($stdout)
|
96
116
|
end
|
97
117
|
memoize :reporter
|
98
118
|
|
99
|
-
|
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
|
-
# @
|
121
|
+
# @return [Mutant::Matcher]
|
121
122
|
#
|
122
|
-
# @
|
123
|
+
# @raise [CLI::Error]
|
124
|
+
# raises error when matcher is not given
|
123
125
|
#
|
124
126
|
# @api private
|
125
127
|
#
|
126
|
-
def
|
127
|
-
|
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
|
-
|
136
|
-
matcher
|
133
|
+
Matcher::Chain.build(@matchers)
|
137
134
|
end
|
135
|
+
memoize :matcher
|
138
136
|
|
139
|
-
#
|
137
|
+
# Add mutation filter
|
138
|
+
#
|
139
|
+
# @param [Class<Mutant::Filter>] klass
|
140
140
|
#
|
141
|
-
# @param [
|
141
|
+
# @param [String] filter
|
142
142
|
#
|
143
|
-
# @return [
|
143
|
+
# @return [undefined]
|
144
144
|
#
|
145
145
|
# @api private
|
146
146
|
#
|
147
|
-
def
|
148
|
-
@
|
147
|
+
def add_filter(klass,filter)
|
148
|
+
@filters << klass.new(filter)
|
149
149
|
end
|
150
150
|
|
151
|
-
#
|
152
|
-
#
|
153
|
-
# @return [String]
|
151
|
+
# Set debug mode
|
154
152
|
#
|
155
153
|
# @api private
|
156
154
|
#
|
157
|
-
|
158
|
-
|
155
|
+
# @return [undefined]
|
156
|
+
#
|
157
|
+
def set_debug
|
158
|
+
@debug = true
|
159
159
|
end
|
160
160
|
|
161
|
-
#
|
162
|
-
#
|
163
|
-
# @return [String]
|
161
|
+
# Set strategy
|
164
162
|
#
|
165
|
-
# @
|
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
|
-
|
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
|
-
#
|
191
|
-
#
|
192
|
-
# @param [Fixnum] amount
|
193
|
-
# the amount of arguments to be consumed
|
173
|
+
# Parse the command-line options
|
194
174
|
#
|
195
|
-
# @
|
175
|
+
# @param [Array<String>] arguments
|
176
|
+
# Command-line options and arguments to be parsed.
|
196
177
|
#
|
197
|
-
# @
|
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
|
210
|
-
|
211
|
-
|
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
|
-
|
214
|
-
|
191
|
+
add_strategies(opts)
|
192
|
+
add_options(opts)
|
215
193
|
end
|
216
194
|
|
217
|
-
|
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
|
-
|
202
|
+
parse_matchers(matchers)
|
220
203
|
end
|
221
204
|
|
222
|
-
#
|
205
|
+
# Parse matchers
|
223
206
|
#
|
224
|
-
# @
|
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
|
245
|
-
|
246
|
-
|
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
|
220
|
+
# Add strategies
|
250
221
|
#
|
251
|
-
# @
|
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
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
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
|
-
#
|
238
|
+
# Add options
|
274
239
|
#
|
275
|
-
# @
|
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
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
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
|
-
|
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
@@ -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
|
data/lib/mutant/constants.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
module Mutant
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
49
|
-
|
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,
|
data/lib/mutant/context/scope.rb
CHANGED
@@ -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 [
|
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 [
|
32
|
+
# @param [Class, Module] scope
|
33
|
+
# @param [Parser::AST::Node] node
|
23
34
|
#
|
24
|
-
# @return [
|
35
|
+
# @return [Parser::AST::Class]
|
25
36
|
# if scope is of kind Class
|
26
37
|
#
|
27
|
-
# @return [
|
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
|
-
|
47
|
+
s(:class, name, nil, node)
|
37
48
|
when ::Module
|
38
|
-
|
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
|
-
|
142
|
-
|
143
|
-
end
|
122
|
+
|
123
|
+
end # Scope
|
124
|
+
end # Context
|
125
|
+
end # Mutant
|
data/lib/mutant/context.rb
CHANGED
@@ -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
|
-
# @
|
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
|
16
|
+
# Return identification
|
15
17
|
#
|
16
18
|
# @return [String]
|
17
19
|
#
|
18
20
|
# @api private
|
19
21
|
#
|
20
|
-
|
21
|
-
|
22
|
-
private
|
22
|
+
abstract_method :identification
|
23
23
|
|
24
|
-
|
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
|