mutant 0.1.1 → 0.2.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.
- data/.gitignore +5 -11
- data/.rspec +0 -1
- data/.travis.yml +14 -3
- data/Changelog.md +3 -0
- data/Gemfile +5 -1
- data/Gemfile.devtools +49 -0
- data/Guardfile +18 -0
- data/README.md +67 -0
- data/Rakefile +4 -1
- data/TODO +13 -0
- data/bin/mutant +14 -0
- data/bin/zombie +14 -0
- data/config/flay.yml +3 -0
- data/config/flog.yml +2 -0
- data/config/roodi.yml +26 -0
- data/config/site.reek +93 -0
- data/config/yardstick.yml +2 -0
- data/lib/inflector.rb +7 -0
- data/lib/inflector/defaults.rb +62 -0
- data/lib/inflector/inflections.rb +209 -0
- data/lib/inflector/methods.rb +149 -0
- data/lib/inflector/version.rb +3 -0
- data/lib/mutant.rb +96 -21
- data/lib/mutant/cli.rb +309 -0
- data/lib/mutant/color.rb +61 -0
- data/lib/mutant/context.rb +36 -0
- data/lib/mutant/context/scope.rb +138 -0
- data/lib/mutant/differ.rb +100 -0
- data/lib/mutant/helper.rb +38 -0
- data/lib/mutant/killer.rb +136 -0
- data/lib/mutant/killer/forking.rb +41 -0
- data/lib/mutant/killer/rspec.rb +49 -0
- data/lib/mutant/killer/static.rb +19 -0
- data/lib/mutant/loader.rb +129 -0
- data/lib/mutant/matcher.rb +55 -0
- data/lib/mutant/matcher/chain.rb +66 -0
- data/lib/mutant/matcher/method.rb +173 -0
- data/lib/mutant/matcher/method/classifier.rb +126 -0
- data/lib/mutant/matcher/method/instance.rb +67 -0
- data/lib/mutant/matcher/method/singleton.rb +141 -0
- data/lib/mutant/matcher/object_space.rb +114 -0
- data/lib/mutant/matcher/scope_methods.rb +127 -0
- data/lib/mutant/mutation.rb +101 -12
- data/lib/mutant/mutation/filter.rb +75 -0
- data/lib/mutant/mutation/filter/code.rb +68 -0
- data/lib/mutant/mutation/filter/regexp.rb +39 -0
- data/lib/mutant/mutation/filter/whitelist.rb +47 -0
- data/lib/mutant/mutator.rb +134 -30
- data/lib/mutant/mutator/node.rb +163 -0
- data/lib/mutant/mutator/node/arguments.rb +24 -0
- data/lib/mutant/mutator/node/block.rb +24 -0
- data/lib/mutant/mutator/node/define.rb +24 -0
- data/lib/mutant/mutator/node/if_statement.rb +93 -0
- data/lib/mutant/mutator/node/literal.rb +54 -0
- data/lib/mutant/mutator/node/literal/array.rb +28 -0
- data/lib/mutant/mutator/node/literal/boolean.rb +49 -0
- data/lib/mutant/mutator/node/literal/dynamic.rb +24 -0
- data/lib/mutant/mutator/node/literal/empty_array.rb +26 -0
- data/lib/mutant/mutator/node/literal/fixnum.rb +37 -0
- data/lib/mutant/mutator/node/literal/float.rb +48 -0
- data/lib/mutant/mutator/node/literal/hash.rb +89 -0
- data/lib/mutant/mutator/node/literal/nil.rb +25 -0
- data/lib/mutant/mutator/node/literal/range.rb +94 -0
- data/lib/mutant/mutator/node/literal/regex.rb +43 -0
- data/lib/mutant/mutator/node/literal/string.rb +26 -0
- data/lib/mutant/mutator/node/literal/symbol.rb +26 -0
- data/lib/mutant/mutator/node/noop.rb +55 -0
- data/lib/mutant/mutator/node/receiver_case.rb +140 -0
- data/lib/mutant/mutator/node/return.rb +31 -0
- data/lib/mutant/mutator/node/send.rb +112 -0
- data/lib/mutant/mutator/registry.rb +48 -0
- data/lib/mutant/mutator/util.rb +87 -0
- data/lib/mutant/random.rb +24 -27
- data/lib/mutant/reporter.rb +48 -30
- data/lib/mutant/reporter/cli.rb +221 -0
- data/lib/mutant/reporter/null.rb +42 -0
- data/lib/mutant/reporter/stats.rb +64 -0
- data/lib/mutant/runner.rb +112 -0
- data/lib/mutant/strategy.rb +42 -0
- data/lib/mutant/strategy/rspec.rb +59 -0
- data/lib/mutant/strategy/rspec/example_lookup.rb +122 -0
- data/lib/mutant/subject.rb +115 -0
- data/lib/mutant/support/method_object.rb +31 -0
- data/locator.rb +87 -0
- data/mutant.gemspec +21 -21
- data/spec/integration/mutant/differ_spec.rb +15 -0
- data/spec/integration/mutant/loader_spec.rb +21 -0
- data/spec/integration/mutant/method_matching_spec.rb +269 -0
- data/spec/integration/mutant/rspec_killer_spec.rb +24 -0
- data/spec/integration/mutant/runner_spec.rb +26 -0
- data/spec/integration/mutant/zombie_spec.rb +8 -0
- data/spec/rcov.opts +7 -0
- data/spec/shared/command_method_behavior.rb +7 -0
- data/spec/shared/each_method_behaviour.rb +15 -0
- data/spec/shared/hash_method_behavior.rb +17 -0
- data/spec/shared/idempotent_method_behavior.rb +7 -0
- data/spec/shared/invertible_method_behaviour.rb +9 -0
- data/spec/shared/method_filter_parse_behavior.rb +16 -0
- data/spec/shared/method_match_behavior.rb +39 -0
- data/spec/shared/mutator_behavior.rb +46 -0
- data/spec/spec_helper.rb +11 -14
- data/spec/support/compress_helper.rb +10 -0
- data/spec/support/rspec.rb +22 -0
- data/spec/support/test_app.rb +5 -0
- data/spec/support/zombie.rb +141 -0
- data/spec/unit/mutant/cli/class_methods/new_spec.rb +87 -0
- data/spec/unit/mutant/cli/class_methods/run_spec.rb +38 -0
- data/spec/unit/mutant/context/root_spec.rb +11 -0
- data/spec/unit/mutant/context/scope/class_methods/build_spec.rb +29 -0
- data/spec/unit/mutant/context/scope/root_spec.rb +22 -0
- data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +27 -0
- data/spec/unit/mutant/killer/fail_ques_spec.rb +39 -0
- data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +32 -0
- data/spec/unit/mutant/loader/eval/class_methods/run_spec.rb +33 -0
- data/spec/unit/mutant/loader/rubinius/class_methods/run_spec.rb +42 -0
- data/spec/unit/mutant/matcher/chain/each_spec.rb +37 -0
- data/spec/unit/mutant/matcher/chain/matchers_spec.rb +12 -0
- data/spec/unit/mutant/matcher/class_methods/from_string_spec.rb +49 -0
- data/spec/unit/mutant/matcher/class_methods/parse_spec.rb +12 -0
- data/spec/unit/mutant/matcher/each_spec.rb +14 -0
- data/spec/unit/mutant/matcher/method/class_methods/parse_spec.rb +21 -0
- data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +34 -0
- data/spec/unit/mutant/matcher/method/method_spec.rb +11 -0
- data/spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb +24 -0
- data/spec/unit/mutant/matcher/object_space/each_spec.rb +31 -0
- data/spec/unit/mutant/mutator/each_spec.rb +25 -0
- data/spec/unit/mutant/mutator/emit_new_spec.rb +51 -0
- data/spec/unit/mutant/mutator/emit_spec.rb +52 -0
- data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +36 -0
- data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +47 -0
- data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +30 -0
- data/spec/unit/mutant/mutator/node/literal/array_spec.rb +30 -0
- data/spec/unit/mutant/mutator/node/literal/boolean/mutation_spec.rb +23 -0
- data/spec/unit/mutant/mutator/node/literal/empty_array_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +25 -0
- data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +34 -0
- data/spec/unit/mutant/mutator/node/literal/nil_spec.rb +13 -0
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +35 -0
- data/spec/unit/mutant/mutator/node/literal/regex_spec.rb +23 -0
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +17 -0
- data/spec/unit/mutant/mutator/node/receiver_case/mutation_spec.rb +27 -0
- data/spec/unit/mutant/mutator/node/return/mutation_spec.rb +21 -0
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +78 -0
- data/spec/unit/mutant/mutator/self_spec.rb +7 -0
- data/spec/unit/mutant/subject/class_methods/new_spec.rb +13 -0
- data/spec/unit/mutant/subject/context_spec.rb +14 -0
- data/spec/unit/mutant/subject/each_spec.rb +35 -0
- data/spec/unit/mutant/subject/node_spec.rb +13 -0
- data/tasks/metrics/ci.rake +7 -0
- data/tasks/metrics/flay.rake +41 -0
- data/tasks/metrics/flog.rake +43 -0
- data/tasks/metrics/heckle.rake +216 -0
- data/tasks/metrics/metric_fu.rake +31 -0
- data/tasks/metrics/reek.rake +15 -0
- data/tasks/metrics/roodi.rake +15 -0
- data/tasks/metrics/yardstick.rake +23 -0
- data/tasks/spec.rake +45 -0
- data/tasks/yard.rake +9 -0
- data/test_app/.rspec +1 -0
- data/test_app/lib/test_app.rb +5 -0
- data/test_app/lib/test_app/literal.rb +32 -0
- data/test_app/spec/shared/command_method_behavior.rb +7 -0
- data/test_app/spec/shared/each_method_behaviour.rb +15 -0
- data/test_app/spec/shared/hash_method_behavior.rb +17 -0
- data/test_app/spec/shared/idempotent_method_behavior.rb +7 -0
- data/test_app/spec/shared/invertible_method_behaviour.rb +9 -0
- data/test_app/spec/shared/method_filter_parse_behavior.rb +16 -0
- data/test_app/spec/shared/method_match_behavior.rb +39 -0
- data/test_app/spec/shared/mutator_behavior.rb +44 -0
- data/test_app/spec/spec_helper.rb +7 -0
- data/test_app/spec/unit/test_app/literal/command_spec.rb +9 -0
- data/test_app/spec/unit/test_app/literal/string_spec.rb +9 -0
- metadata +346 -124
- data/.rvmrc +0 -1
- data/Readme.md +0 -13
- data/exe/mutate +0 -6
- data/lib/mutant/extensions.rb +0 -8
- data/lib/mutant/formatter.rb +0 -19
- data/lib/mutant/implementation.rb +0 -70
- data/lib/mutant/literal.rb +0 -147
- data/lib/mutant/method.rb +0 -31
- data/lib/mutant/mutatee.rb +0 -61
- data/lib/mutant/node.rb +0 -26
- data/lib/mutant/runners/rspec.rb +0 -34
- data/lib/mutant/version.rb +0 -3
- data/spec/functional/class_spec.rb +0 -46
- data/spec/functional/instance_method/array_spec.rb +0 -53
- data/spec/functional/instance_method/boolean_spec.rb +0 -101
- data/spec/functional/instance_method/call_spec.rb +0 -161
- data/spec/functional/instance_method/fixnum_spec.rb +0 -53
- data/spec/functional/instance_method/float_spec.rb +0 -53
- data/spec/functional/instance_method/hash_spec.rb +0 -53
- data/spec/functional/instance_method/if_spec.rb +0 -57
- data/spec/functional/instance_method/ivar_assign_spec.rb +0 -62
- data/spec/functional/instance_method/range_spec.rb +0 -53
- data/spec/functional/instance_method/regex_spec.rb +0 -55
- data/spec/functional/instance_method/string_spec.rb +0 -53
- data/spec/functional/instance_method/symbol_spec.rb +0 -53
- data/spec/functional/reporter/method_loaded_spec.rb +0 -62
- data/spec/functional/reporter/running_mutations_spec.rb +0 -60
- data/spec/functional/runners/rspec_spec.rb +0 -26
- data/spec/functional/singleton_method/array_spec.rb +0 -53
- data/spec/functional/singleton_method/boolean_spec.rb +0 -101
- data/spec/functional/singleton_method/call_spec.rb +0 -161
- data/spec/functional/singleton_method/fixnum_spec.rb +0 -53
- data/spec/functional/singleton_method/float_spec.rb +0 -53
- data/spec/functional/singleton_method/hash_spec.rb +0 -53
- data/spec/functional/singleton_method/if_spec.rb +0 -57
- data/spec/functional/singleton_method/ivar_assign_spec.rb +0 -60
- data/spec/functional/singleton_method/range_spec.rb +0 -53
- data/spec/functional/singleton_method/regex_spec.rb +0 -55
- data/spec/functional/singleton_method/string_spec.rb +0 -53
- data/spec/functional/singleton_method/symbol_spec.rb +0 -53
- data/spec/mutant/extensions_spec.rb +0 -13
- data/spec/mutant/implementation_spec.rb +0 -223
- data/spec/mutant/literal_spec.rb +0 -129
- data/spec/mutant/mutatee_spec.rb +0 -28
- data/spec/mutant/node_spec.rb +0 -41
- data/spec/mutant/random_spec.rb +0 -33
- data/spec/mutant/reporter_spec.rb +0 -17
- data/spec/mutant_spec.rb +0 -28
- data/spec/support/example_group_helpers.rb +0 -11
- data/spec/support/example_helpers.rb +0 -5
data/lib/mutant/cli.rb
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
# Comandline parser
|
|
3
|
+
class CLI
|
|
4
|
+
include Adamantium::Flat, Equalizer.new(:matcher, :filter, :killer)
|
|
5
|
+
|
|
6
|
+
# Error raised when CLI argv is inalid
|
|
7
|
+
Error = Class.new(RuntimeError)
|
|
8
|
+
|
|
9
|
+
EXIT_FAILURE = 1
|
|
10
|
+
EXIT_SUCCESS = 0
|
|
11
|
+
|
|
12
|
+
# Run cli with arguments
|
|
13
|
+
#
|
|
14
|
+
# @param [Array<String>] arguments
|
|
15
|
+
#
|
|
16
|
+
# @return [Fixnum]
|
|
17
|
+
# returns exit status
|
|
18
|
+
#
|
|
19
|
+
# @api private
|
|
20
|
+
#
|
|
21
|
+
def self.run(*arguments)
|
|
22
|
+
error = Runner.run(new(*arguments)).fail?
|
|
23
|
+
error ? EXIT_FAILURE : EXIT_SUCCESS
|
|
24
|
+
rescue Error => exception
|
|
25
|
+
$stderr.puts(exception.message)
|
|
26
|
+
EXIT_FAILURE
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Return matcher
|
|
30
|
+
#
|
|
31
|
+
# @return [Mutant::Matcher]
|
|
32
|
+
#
|
|
33
|
+
# @raise [CLI::Error]
|
|
34
|
+
# raises error when matcher is not given
|
|
35
|
+
#
|
|
36
|
+
# @api private
|
|
37
|
+
#
|
|
38
|
+
def matcher
|
|
39
|
+
if @matchers.empty?
|
|
40
|
+
raise Error, 'No matchers given'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Mutant::Matcher::Chain.build(@matchers)
|
|
44
|
+
end
|
|
45
|
+
memoize :matcher
|
|
46
|
+
|
|
47
|
+
# Return mutation filter
|
|
48
|
+
#
|
|
49
|
+
# @return [Mutant::Matcher]
|
|
50
|
+
#
|
|
51
|
+
# @api private
|
|
52
|
+
#
|
|
53
|
+
def filter
|
|
54
|
+
if @filters.empty?
|
|
55
|
+
Mutation::Filter::ALL
|
|
56
|
+
else
|
|
57
|
+
Mutation::Filter::Whitelist.new(@filters)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
memoize :filter
|
|
61
|
+
|
|
62
|
+
# Return stratety
|
|
63
|
+
#
|
|
64
|
+
# @return [Strategy]
|
|
65
|
+
#
|
|
66
|
+
# @api private
|
|
67
|
+
#
|
|
68
|
+
def strategy
|
|
69
|
+
@strategy || raise(Error, 'no strategy was set!')
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# Return reporter
|
|
73
|
+
#
|
|
74
|
+
# @return [Mutant::Reporter::CLI]
|
|
75
|
+
#
|
|
76
|
+
# @api private
|
|
77
|
+
#
|
|
78
|
+
def reporter
|
|
79
|
+
Mutant::Reporter::CLI.new($stdout)
|
|
80
|
+
end
|
|
81
|
+
memoize :reporter
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
OPTIONS = {
|
|
86
|
+
'--code' => [:add_filter, Mutation::Filter::Code ],
|
|
87
|
+
'-I' => [:add_load_path ],
|
|
88
|
+
'--include' => [:add_load_path ],
|
|
89
|
+
'-r' => [:require_library ],
|
|
90
|
+
'--require' => [:require_library ],
|
|
91
|
+
#'--killer-fork' => [:enable_killer_fork ],
|
|
92
|
+
'--rspec-unit' => [:set_strategy, Strategy::Rspec::Unit ],
|
|
93
|
+
'--rspec-full' => [:set_strategy, Strategy::Rspec::Full ],
|
|
94
|
+
'--rspec-dm2' => [:set_strategy, Strategy::Rspec::DM2 ],
|
|
95
|
+
'--static-fail' => [:set_strategy, Strategy::Static::Fail ],
|
|
96
|
+
'--static-success' => [:set_strategy, Strategy::Static::Success ]
|
|
97
|
+
}.freeze
|
|
98
|
+
|
|
99
|
+
OPTION_PATTERN = %r(\A-(?:-)?[a-zA-Z0-9\-]+\z).freeze
|
|
100
|
+
|
|
101
|
+
# Return selected killer
|
|
102
|
+
#
|
|
103
|
+
# @return [Killer]
|
|
104
|
+
#
|
|
105
|
+
# @api private
|
|
106
|
+
#
|
|
107
|
+
def selected_killer
|
|
108
|
+
unless @rspec
|
|
109
|
+
raise Error, "Only rspec is supported currently use --rspec switch"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
Mutant::Killer::Rspec
|
|
113
|
+
end
|
|
114
|
+
memoize :selected_killer
|
|
115
|
+
|
|
116
|
+
# Return option for argument with index
|
|
117
|
+
#
|
|
118
|
+
# @param [Fixnum] index
|
|
119
|
+
#
|
|
120
|
+
# @return [String]
|
|
121
|
+
#
|
|
122
|
+
# @api private
|
|
123
|
+
#
|
|
124
|
+
def option(index)
|
|
125
|
+
@arguments.fetch(index+1)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# Initialize CLI
|
|
129
|
+
#
|
|
130
|
+
# @param [Array<String>] arguments
|
|
131
|
+
#
|
|
132
|
+
# @return [undefined]
|
|
133
|
+
#
|
|
134
|
+
# @api private
|
|
135
|
+
#
|
|
136
|
+
def initialize(arguments)
|
|
137
|
+
@filters, @matchers = [], []
|
|
138
|
+
|
|
139
|
+
@arguments, @index = arguments, 0
|
|
140
|
+
|
|
141
|
+
while @index < @arguments.length
|
|
142
|
+
dispatch
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
strategy
|
|
146
|
+
matcher
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
# Return current argument
|
|
150
|
+
#
|
|
151
|
+
# @return [String]
|
|
152
|
+
#
|
|
153
|
+
# @api private
|
|
154
|
+
#
|
|
155
|
+
def current_argument
|
|
156
|
+
@arguments.fetch(@index)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Return current option value
|
|
160
|
+
#
|
|
161
|
+
# @return [String]
|
|
162
|
+
#
|
|
163
|
+
# @raise [CLI::Error]
|
|
164
|
+
# raises error when option is missing
|
|
165
|
+
#
|
|
166
|
+
# @api private
|
|
167
|
+
#
|
|
168
|
+
def current_option_value
|
|
169
|
+
@arguments.fetch(@index+1)
|
|
170
|
+
rescue IndexError
|
|
171
|
+
raise Error, "#{current_argument.inspect} is missing an argument"
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# Process current argument
|
|
175
|
+
#
|
|
176
|
+
# @return [undefined]
|
|
177
|
+
#
|
|
178
|
+
# @api private
|
|
179
|
+
#
|
|
180
|
+
def dispatch
|
|
181
|
+
if OPTION_PATTERN =~ current_argument
|
|
182
|
+
dispatch_option
|
|
183
|
+
else
|
|
184
|
+
dispatch_matcher
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
# Move processed argument by amount
|
|
189
|
+
#
|
|
190
|
+
# @param [Fixnum] amount
|
|
191
|
+
# the amount of arguments to be consumed
|
|
192
|
+
#
|
|
193
|
+
# @return [undefined]
|
|
194
|
+
#
|
|
195
|
+
# @api private
|
|
196
|
+
#
|
|
197
|
+
def consume(amount)
|
|
198
|
+
@index += amount
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# Process matcher argument
|
|
202
|
+
#
|
|
203
|
+
# @return [undefined]
|
|
204
|
+
#
|
|
205
|
+
# @api private
|
|
206
|
+
#
|
|
207
|
+
def dispatch_matcher
|
|
208
|
+
argument = current_argument
|
|
209
|
+
matcher = Mutant::Matcher.from_string(argument)
|
|
210
|
+
|
|
211
|
+
unless matcher
|
|
212
|
+
raise Error, "Invalid matcher syntax: #{argument.inspect}"
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
@matchers << matcher
|
|
216
|
+
|
|
217
|
+
consume(1)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
# Process option argument
|
|
221
|
+
#
|
|
222
|
+
# @return [Undefined]
|
|
223
|
+
#
|
|
224
|
+
# @api private
|
|
225
|
+
#
|
|
226
|
+
def dispatch_option
|
|
227
|
+
argument = current_argument
|
|
228
|
+
arguments = *OPTIONS.fetch(argument) do
|
|
229
|
+
raise Error, "Unknown option: #{argument.inspect}"
|
|
230
|
+
end
|
|
231
|
+
send(*arguments)
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Add mutation filter
|
|
235
|
+
#
|
|
236
|
+
# @param [Class<Mutant::Filter>]
|
|
237
|
+
#
|
|
238
|
+
# @return [undefined]
|
|
239
|
+
#
|
|
240
|
+
# @api private
|
|
241
|
+
#
|
|
242
|
+
def add_filter(klass)
|
|
243
|
+
@filters << klass.new(current_option_value)
|
|
244
|
+
consume(2)
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# Add load path
|
|
248
|
+
#
|
|
249
|
+
# @api private
|
|
250
|
+
#
|
|
251
|
+
# @return [undefined]
|
|
252
|
+
#
|
|
253
|
+
def add_load_path
|
|
254
|
+
$LOAD_PATH << current_option_value
|
|
255
|
+
consume(2)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Enable rspec
|
|
259
|
+
#
|
|
260
|
+
# @api private
|
|
261
|
+
#
|
|
262
|
+
# @return [self]
|
|
263
|
+
#
|
|
264
|
+
# @api private
|
|
265
|
+
#
|
|
266
|
+
def enable_rspec
|
|
267
|
+
consume(1)
|
|
268
|
+
@rspec = true
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Enable killer forking
|
|
272
|
+
#
|
|
273
|
+
# @api private
|
|
274
|
+
#
|
|
275
|
+
# @return [self]
|
|
276
|
+
#
|
|
277
|
+
# @api private
|
|
278
|
+
#
|
|
279
|
+
def enable_killer_fork
|
|
280
|
+
consume(1)
|
|
281
|
+
@forking = true
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Set strategy
|
|
285
|
+
#
|
|
286
|
+
# @param [Strategy]
|
|
287
|
+
#
|
|
288
|
+
# @api private
|
|
289
|
+
#
|
|
290
|
+
# @return [undefined]
|
|
291
|
+
#
|
|
292
|
+
def set_strategy(strategy)
|
|
293
|
+
consume(1)
|
|
294
|
+
@strategy = strategy
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
# Require library
|
|
298
|
+
#
|
|
299
|
+
# @api private
|
|
300
|
+
#
|
|
301
|
+
# @return [undefined]
|
|
302
|
+
#
|
|
303
|
+
def require_library
|
|
304
|
+
require(current_option_value)
|
|
305
|
+
consume(2)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
end
|
|
309
|
+
end
|
data/lib/mutant/color.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
# Class to colorize strings
|
|
3
|
+
class Color
|
|
4
|
+
include Adamantium::Flat
|
|
5
|
+
|
|
6
|
+
# Initialize color object
|
|
7
|
+
#
|
|
8
|
+
# @param [Fixnum] code
|
|
9
|
+
#
|
|
10
|
+
# @return [undefined]
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
13
|
+
#
|
|
14
|
+
def initialize(code)
|
|
15
|
+
@code = code
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Format text with color
|
|
19
|
+
#
|
|
20
|
+
# @param [String] text
|
|
21
|
+
#
|
|
22
|
+
# @return [String]
|
|
23
|
+
#
|
|
24
|
+
# @api private
|
|
25
|
+
#
|
|
26
|
+
def format(text)
|
|
27
|
+
"\e[#{@code}m#{text}\e[0m"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
NONE = Class.new(self) do
|
|
31
|
+
# Format null color
|
|
32
|
+
#
|
|
33
|
+
# @param [String] text
|
|
34
|
+
#
|
|
35
|
+
# @return [String]
|
|
36
|
+
# returns the argument string
|
|
37
|
+
#
|
|
38
|
+
# @api private
|
|
39
|
+
#
|
|
40
|
+
def format(text)
|
|
41
|
+
text
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
# Initialize null color
|
|
47
|
+
#
|
|
48
|
+
# @return [undefined]
|
|
49
|
+
#
|
|
50
|
+
# @api private
|
|
51
|
+
#
|
|
52
|
+
def initialize(*)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end.new.freeze
|
|
56
|
+
|
|
57
|
+
RED = Color.new(31)
|
|
58
|
+
GREEN = Color.new(32)
|
|
59
|
+
BLUE = Color.new(34)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
# An abstract context where mutations can be appied to.
|
|
3
|
+
class Context
|
|
4
|
+
include Adamantium::Flat, AbstractType
|
|
5
|
+
|
|
6
|
+
# Return root ast node
|
|
7
|
+
#
|
|
8
|
+
# @return [Rubinis::AST::Script]
|
|
9
|
+
#
|
|
10
|
+
# @api private
|
|
11
|
+
#
|
|
12
|
+
abstract_method :root
|
|
13
|
+
|
|
14
|
+
# Return source path
|
|
15
|
+
#
|
|
16
|
+
# @return [String]
|
|
17
|
+
#
|
|
18
|
+
# @api private
|
|
19
|
+
#
|
|
20
|
+
attr_reader :source_path
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
# Initialize context
|
|
25
|
+
#
|
|
26
|
+
# @param [String] source_path
|
|
27
|
+
#
|
|
28
|
+
# @return [undefined]
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
31
|
+
#
|
|
32
|
+
def initialize(source_path)
|
|
33
|
+
@source_path = source_path
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
module Mutant
|
|
2
|
+
class Context
|
|
3
|
+
# Scope context for mutation (Class or Module)
|
|
4
|
+
class Scope < self
|
|
5
|
+
include Adamantium::Flat, AbstractType, Equalizer.new(:scope, :source_path)
|
|
6
|
+
|
|
7
|
+
# Class context for mutation
|
|
8
|
+
class Class < self
|
|
9
|
+
SCOPE_CLASS = Rubinius::AST::ClassScope
|
|
10
|
+
KEYWORD = 'class'.freeze
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# Module context for mutation
|
|
14
|
+
class Module < self
|
|
15
|
+
SCOPE_CLASS = Rubinius::AST::ModuleScope
|
|
16
|
+
KEYWORD = 'module'.freeze
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
TABLE = {
|
|
20
|
+
::Module => Module,
|
|
21
|
+
::Class => Class
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
# Build scope context from class or module
|
|
25
|
+
#
|
|
26
|
+
# @param [String] source_path
|
|
27
|
+
#
|
|
28
|
+
# @param [::Class|::Module] scope
|
|
29
|
+
#
|
|
30
|
+
# @return [Context::Scope]
|
|
31
|
+
#
|
|
32
|
+
# @api private
|
|
33
|
+
#
|
|
34
|
+
def self.build(scope, source_path)
|
|
35
|
+
scope_class = scope.class
|
|
36
|
+
klass = TABLE.fetch(scope_class) do
|
|
37
|
+
raise ArgumentError, "Can only build mutation scope from class or module got: #{scope_class.inspect}"
|
|
38
|
+
end.new(scope, source_path)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Return AST wrapping mutated node
|
|
42
|
+
#
|
|
43
|
+
# @return [Rubinius::AST::Script]
|
|
44
|
+
#
|
|
45
|
+
# @api private
|
|
46
|
+
#
|
|
47
|
+
def root(node)
|
|
48
|
+
root = root_ast
|
|
49
|
+
block = Rubinius::AST::Block.new(1, [node])
|
|
50
|
+
root.body = scope_class.new(1, root.name, block)
|
|
51
|
+
root
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Return unqualified name of scope
|
|
55
|
+
#
|
|
56
|
+
# @return [String]
|
|
57
|
+
#
|
|
58
|
+
# @api private
|
|
59
|
+
#
|
|
60
|
+
def unqualified_name
|
|
61
|
+
name_nesting.last
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Return scope wrapped by context
|
|
65
|
+
#
|
|
66
|
+
# @return [::Module|::Class]
|
|
67
|
+
#
|
|
68
|
+
# @api private
|
|
69
|
+
#
|
|
70
|
+
attr_reader :scope
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# Initialize object
|
|
75
|
+
#
|
|
76
|
+
# @param [Object] scope
|
|
77
|
+
# @param [String] source_path
|
|
78
|
+
#
|
|
79
|
+
# @api private
|
|
80
|
+
#
|
|
81
|
+
def initialize(scope, source_path)
|
|
82
|
+
super(source_path)
|
|
83
|
+
@scope = scope
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# Return scope AST class
|
|
87
|
+
#
|
|
88
|
+
# @return [Rubinius::AST::Node]
|
|
89
|
+
#
|
|
90
|
+
# @api private
|
|
91
|
+
#
|
|
92
|
+
def scope_class
|
|
93
|
+
self.class::SCOPE_CLASS
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Return keyword
|
|
97
|
+
#
|
|
98
|
+
# @return [Rubinius::AST::Node]
|
|
99
|
+
#
|
|
100
|
+
# @api private
|
|
101
|
+
#
|
|
102
|
+
def keyword
|
|
103
|
+
self.class::KEYWORD
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# Return new root ast
|
|
107
|
+
#
|
|
108
|
+
# @return [Rubinius::AST::Node]
|
|
109
|
+
#
|
|
110
|
+
# @api private
|
|
111
|
+
#
|
|
112
|
+
def root_ast
|
|
113
|
+
"#{keyword} #{qualified_name}; end".to_ast
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Return qualified name of scope
|
|
117
|
+
#
|
|
118
|
+
# @return [String]
|
|
119
|
+
#
|
|
120
|
+
# @api private
|
|
121
|
+
#
|
|
122
|
+
def qualified_name
|
|
123
|
+
scope.name
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Return nesting of names of scope
|
|
127
|
+
#
|
|
128
|
+
# @return [Array<String>]
|
|
129
|
+
#
|
|
130
|
+
# @api private
|
|
131
|
+
#
|
|
132
|
+
def name_nesting
|
|
133
|
+
scope.name.split('::')
|
|
134
|
+
end
|
|
135
|
+
memoize :name_nesting
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|