mutant 0.2.20 → 0.3.0.beta2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|