mutant 0.8.20 → 0.8.21
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 +4 -4
- data/.circleci/config.yml +0 -2
- data/Changelog.md +4 -0
- data/Gemfile.lock +17 -18
- data/README.md +21 -4
- data/config/rubocop.yml +3 -4
- data/docs/mutant-minitest.md +4 -2
- data/docs/mutant-rspec.md +104 -14
- data/lib/mutant.rb +2 -1
- data/lib/mutant/ast/meta/send.rb +1 -15
- data/lib/mutant/ast/types.rb +47 -22
- data/lib/mutant/meta.rb +2 -2
- data/lib/mutant/meta/example.rb +2 -1
- data/lib/mutant/meta/example/dsl.rb +12 -9
- data/lib/mutant/meta/example/verification.rb +34 -16
- data/lib/mutant/mutator/node.rb +7 -0
- data/lib/mutant/mutator/node/argument.rb +0 -1
- data/lib/mutant/mutator/node/arguments.rb +13 -1
- data/lib/mutant/mutator/node/block.rb +1 -1
- data/lib/mutant/mutator/node/index.rb +129 -0
- data/lib/mutant/mutator/node/noop.rb +1 -1
- data/lib/mutant/mutator/node/procarg_zero.rb +45 -0
- data/lib/mutant/mutator/node/send.rb +1 -27
- data/lib/mutant/parser.rb +1 -1
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +34 -32
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warning_filter.rb +1 -1
- data/lib/mutant/zombifier.rb +1 -1
- data/meta/block.rb +22 -3
- data/meta/index.rb +133 -0
- data/meta/indexasgn.rb +31 -0
- data/meta/lambda.rb +9 -0
- data/meta/regexp.rb +0 -7
- data/meta/regexp/character_types.rb +1 -1
- data/meta/send.rb +0 -146
- data/mutant.gemspec +2 -3
- data/spec/spec_helper.rb +1 -1
- data/spec/support/corpus.rb +28 -12
- data/spec/unit/mutant/ast/meta/send/proc_predicate_spec.rb +1 -1
- data/spec/unit/mutant/ast/meta/send/receiver_possible_top_level_const_predicate_spec.rb +1 -1
- data/spec/unit/mutant/ast/meta/send_spec.rb +6 -8
- data/spec/unit/mutant/meta/example/dsl_spec.rb +9 -9
- data/spec/unit/mutant/meta/example/verification_spec.rb +36 -4
- data/spec/unit/mutant/meta/example_spec.rb +4 -4
- data/spec/unit/mutant/mutator/node_spec.rb +12 -7
- data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +3 -1
- data/spec/unit/mutant/subject_spec.rb +1 -1
- data/spec/unit/mutant/zombifier_spec.rb +1 -1
- metadata +12 -24
- data/config/flay.yml +0 -3
- data/config/flog.yml +0 -2
- data/lib/mutant/mutator/node/send/index.rb +0 -52
data/mutant.gemspec
CHANGED
@@ -36,9 +36,8 @@ Gem::Specification.new do |gem|
|
|
36
36
|
gem.add_runtime_dependency('parser', '~> 2.5.1')
|
37
37
|
gem.add_runtime_dependency('procto', '~> 0.0.2')
|
38
38
|
gem.add_runtime_dependency('regexp_parser', '~> 1.2')
|
39
|
-
gem.add_runtime_dependency('unparser', '~> 0.
|
39
|
+
gem.add_runtime_dependency('unparser', '~> 0.4.1')
|
40
40
|
|
41
|
-
gem.add_development_dependency('
|
42
|
-
gem.add_development_dependency('devtools', '~> 0.1.21')
|
41
|
+
gem.add_development_dependency('devtools', '~> 0.1.22')
|
43
42
|
gem.add_development_dependency('parallel', '~> 1.3')
|
44
43
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/corpus.rb
CHANGED
@@ -87,7 +87,7 @@ module MutantSpec
|
|
87
87
|
in_processes: parallel_processes
|
88
88
|
}
|
89
89
|
|
90
|
-
total = Parallel.map(effective_ruby_paths, options, &method(:
|
90
|
+
total = Parallel.map(effective_ruby_paths, options, &method(:check_generation))
|
91
91
|
.inject(DEFAULT_MUTATION_COUNT, :+)
|
92
92
|
|
93
93
|
took = Mutant::Timer.now - start
|
@@ -129,33 +129,49 @@ module MutantSpec
|
|
129
129
|
# @param path [Pathname] path responsible for exception
|
130
130
|
#
|
131
131
|
# @return [Integer] mutations generated
|
132
|
-
def
|
132
|
+
def check_generation(path)
|
133
133
|
relative_path = path.relative_path_from(repo_path)
|
134
134
|
|
135
|
-
|
135
|
+
node = Parser::CurrentRuby.parse(path.read)
|
136
|
+
fail "Cannot parse: #{path}" unless node
|
137
|
+
|
138
|
+
mutations = Mutant::Mutator.mutate(node)
|
139
|
+
|
140
|
+
mutations.each do |mutation|
|
141
|
+
check_generation_invariants(node, mutation)
|
142
|
+
end
|
136
143
|
|
137
144
|
expected_errors.assert_success(relative_path)
|
138
145
|
|
139
|
-
|
146
|
+
mutations.length
|
140
147
|
rescue Exception => exception # rubocop:disable Lint/RescueException
|
141
148
|
expected_errors.assert_error(relative_path, exception)
|
142
149
|
|
143
150
|
DEFAULT_MUTATION_COUNT
|
144
151
|
end
|
145
152
|
|
146
|
-
#
|
153
|
+
# Check generation invariants
|
147
154
|
#
|
148
|
-
# @param
|
155
|
+
# @param [Parser::AST::Node] original
|
156
|
+
# @param [Parser::AST::Node] mutation
|
149
157
|
#
|
150
|
-
# @
|
158
|
+
# @return [undefined]
|
151
159
|
#
|
152
|
-
# @
|
153
|
-
def
|
154
|
-
|
160
|
+
# @raise [Exception]
|
161
|
+
def check_generation_invariants(original, mutation)
|
162
|
+
return unless ENV['MUTANT_CORPUS_EXPENSIVE']
|
163
|
+
|
164
|
+
original_source = Unparser.unparse(original)
|
165
|
+
mutation_source = Unparser.unparse(mutation)
|
155
166
|
|
156
|
-
|
167
|
+
Mutant::Diff.build(original_source, mutation_source) and return
|
157
168
|
|
158
|
-
Mutant::
|
169
|
+
fail Mutant::Reporter::CLI::NO_DIFF_MESSAGE % [
|
170
|
+
original_source,
|
171
|
+
original.inspect,
|
172
|
+
mutation_source,
|
173
|
+
mutation.inspect
|
174
|
+
]
|
159
175
|
end
|
160
176
|
|
161
177
|
# Install mutant
|
@@ -4,7 +4,7 @@ RSpec.describe Mutant::AST::Meta::Send, '#proc?' do
|
|
4
4
|
subject { described_class.new(node).proc? }
|
5
5
|
|
6
6
|
shared_context 'proc send' do |source|
|
7
|
-
let(:node) {
|
7
|
+
let(:node) { Unparser.parse(source).children.first }
|
8
8
|
end
|
9
9
|
|
10
10
|
shared_examples 'proc definition' do |*args|
|
@@ -4,7 +4,7 @@ RSpec.describe Mutant::AST::Meta::Send, '#receiver_possible_top_level_const?' do
|
|
4
4
|
subject { described_class.new(node).receiver_possible_top_level_const? }
|
5
5
|
|
6
6
|
def parse(source)
|
7
|
-
|
7
|
+
Unparser.parse(source)
|
8
8
|
end
|
9
9
|
|
10
10
|
context 'when implicit top level const' do
|
@@ -4,24 +4,22 @@ RSpec.describe Mutant::AST::Meta::Send do
|
|
4
4
|
let(:object) { described_class.new(node) }
|
5
5
|
|
6
6
|
def parse(source)
|
7
|
-
|
7
|
+
Unparser.parse(source)
|
8
8
|
end
|
9
9
|
|
10
10
|
let(:method_call) { parse('foo.bar(baz)') }
|
11
11
|
let(:attribute_read) { parse('foo.bar') }
|
12
|
-
let(:index_assignment) { parse('foo[0] = bar') }
|
13
12
|
let(:attribute_assignment) { parse('foo.bar = baz') }
|
14
13
|
let(:binary_method_operator) { parse('foo == bar') }
|
15
14
|
|
16
15
|
class Expectation
|
17
|
-
include Adamantium, Anima.new(:name, :
|
16
|
+
include Adamantium, Anima.new(:name, :attribute_assignment, :binary_method_operator)
|
18
17
|
|
19
18
|
ALL = [
|
20
|
-
[:method_call, false, false
|
21
|
-
[:attribute_read, false, false
|
22
|
-
[:
|
23
|
-
[:
|
24
|
-
[:binary_method_operator, false, false, false, true]
|
19
|
+
[:method_call, false, false],
|
20
|
+
[:attribute_read, false, false],
|
21
|
+
[:attribute_assignment, true, false],
|
22
|
+
[:binary_method_operator, false, true]
|
25
23
|
].map do |values|
|
26
24
|
new(Hash[anima.attribute_names.zip(values)])
|
27
25
|
end.freeze
|
@@ -2,19 +2,19 @@
|
|
2
2
|
|
3
3
|
RSpec.describe Mutant::Meta::Example::DSL do
|
4
4
|
describe '.call' do
|
5
|
-
subject { described_class.call(file,
|
5
|
+
subject { described_class.call(file, types, block) }
|
6
6
|
|
7
|
-
let(:file) { 'foo.rb'
|
8
|
-
let(:node) { s(:false)
|
9
|
-
let(:
|
10
|
-
let(:expected) { []
|
7
|
+
let(:file) { 'foo.rb' }
|
8
|
+
let(:node) { s(:false) }
|
9
|
+
let(:types) { Set.new([node.type]) }
|
10
|
+
let(:expected) { [] }
|
11
11
|
|
12
12
|
let(:expected_example) do
|
13
13
|
Mutant::Meta::Example.new(
|
14
|
-
file:
|
15
|
-
node:
|
16
|
-
|
17
|
-
expected:
|
14
|
+
file: file,
|
15
|
+
node: node,
|
16
|
+
types: types,
|
17
|
+
expected: expected
|
18
18
|
)
|
19
19
|
end
|
20
20
|
|
@@ -5,10 +5,10 @@ RSpec.describe Mutant::Meta::Example::Verification do
|
|
5
5
|
|
6
6
|
let(:example) do
|
7
7
|
Mutant::Meta::Example.new(
|
8
|
-
file:
|
9
|
-
node:
|
10
|
-
|
11
|
-
expected:
|
8
|
+
file: 'foo.rb',
|
9
|
+
node: s(:true),
|
10
|
+
types: [:true],
|
11
|
+
expected: expected_nodes
|
12
12
|
)
|
13
13
|
end
|
14
14
|
|
@@ -75,6 +75,7 @@ RSpec.describe Mutant::Meta::Example::Verification do
|
|
75
75
|
- node: s(:nil)
|
76
76
|
source: nil
|
77
77
|
unexpected: []
|
78
|
+
invalid_syntax: []
|
78
79
|
no_diff: []
|
79
80
|
REPORT
|
80
81
|
end
|
@@ -95,6 +96,7 @@ RSpec.describe Mutant::Meta::Example::Verification do
|
|
95
96
|
source: 'false'
|
96
97
|
- node: s(:nil)
|
97
98
|
source: nil
|
99
|
+
invalid_syntax: []
|
98
100
|
no_diff: []
|
99
101
|
REPORT
|
100
102
|
end
|
@@ -112,11 +114,41 @@ RSpec.describe Mutant::Meta::Example::Verification do
|
|
112
114
|
original_source: 'true'
|
113
115
|
missing: []
|
114
116
|
unexpected: []
|
117
|
+
invalid_syntax: []
|
115
118
|
no_diff:
|
116
119
|
- node: s(:true)
|
117
120
|
source: 'true'
|
118
121
|
REPORT
|
119
122
|
end
|
120
123
|
end
|
124
|
+
|
125
|
+
context 'when the generated node is invalid syntax after unparsed' do
|
126
|
+
let(:invalid_node) do
|
127
|
+
s(:op_asgn, s(:send, s(:self), :at, s(:int, 1)), :+, s(:int, 1))
|
128
|
+
end
|
129
|
+
|
130
|
+
let(:expected_nodes) { [invalid_node] }
|
131
|
+
let(:generated_nodes) { [invalid_node] }
|
132
|
+
|
133
|
+
specify do
|
134
|
+
should eql(<<~'REPORT')
|
135
|
+
---
|
136
|
+
file: foo.rb
|
137
|
+
original_ast: s(:true)
|
138
|
+
original_source: 'true'
|
139
|
+
missing: []
|
140
|
+
unexpected: []
|
141
|
+
invalid_syntax:
|
142
|
+
- node: |-
|
143
|
+
s(:op_asgn,
|
144
|
+
s(:send,
|
145
|
+
s(:self), :at,
|
146
|
+
s(:int, 1)), :+,
|
147
|
+
s(:int, 1))
|
148
|
+
source: self.at(1) += 1
|
149
|
+
no_diff: []
|
150
|
+
REPORT
|
151
|
+
end
|
152
|
+
end
|
121
153
|
end
|
122
154
|
end
|
@@ -3,10 +3,10 @@
|
|
3
3
|
RSpec.describe Mutant::Meta::Example do
|
4
4
|
let(:object) do
|
5
5
|
described_class.new(
|
6
|
-
file:
|
7
|
-
node:
|
8
|
-
|
9
|
-
expected:
|
6
|
+
file: file,
|
7
|
+
node: node,
|
8
|
+
types: [node.type],
|
9
|
+
expected: mutation_nodes
|
10
10
|
)
|
11
11
|
end
|
12
12
|
|
@@ -1,15 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
|
4
|
-
RSpec.describe Mutant::Mutator::REGISTRY.lookup(type) do
|
5
|
-
toplevel_nodes = examples.map { |example| example.node.type }.uniq
|
3
|
+
aggregate = Hash.new { |hash, key| hash[key] = [] }
|
6
4
|
|
7
|
-
|
5
|
+
Mutant::Meta::Example::ALL
|
6
|
+
.each_with_object(aggregate) do |example, agg|
|
7
|
+
example.types.each do |type|
|
8
|
+
agg[Mutant::Mutator::REGISTRY.lookup(type)] << example
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
aggregate.each do |mutator, examples|
|
13
|
+
RSpec.describe mutator do
|
14
|
+
it 'generates expected mutations' do
|
8
15
|
examples.each do |example|
|
9
16
|
verification = example.verification
|
10
|
-
unless verification.success?
|
11
|
-
fail verification.error_report
|
12
|
-
end
|
17
|
+
fail verification.error_report unless verification.success?
|
13
18
|
end
|
14
19
|
end
|
15
20
|
end
|
@@ -48,7 +48,9 @@ RSpec.describe Mutant::Reporter::CLI::Printer::MutationResult do
|
|
48
48
|
it_reports(<<~REPORT)
|
49
49
|
evil:subject-a:a5bc7
|
50
50
|
--- Internal failure ---
|
51
|
-
BUG:
|
51
|
+
BUG: A generted mutation did not result in exactly one diff hunk!
|
52
|
+
This is an invariant violation by the mutation generation engine.
|
53
|
+
Please report a reproduction to https://github.com/mbj/mutant
|
52
54
|
Original unparsed source:
|
53
55
|
super
|
54
56
|
Original AST:
|
@@ -80,7 +80,7 @@ RSpec.describe Mutant::Zombifier do
|
|
80
80
|
let(:file_entries) do
|
81
81
|
{
|
82
82
|
'a/project.rb' => { file: true, contents: 'module Project; end' },
|
83
|
-
'b/bar.rb'
|
83
|
+
'b/bar.rb' => { file: true, contents: 'module Bar; end' }
|
84
84
|
}
|
85
85
|
end
|
86
86
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mutant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: abstract_type
|
@@ -198,42 +198,28 @@ dependencies:
|
|
198
198
|
requirements:
|
199
199
|
- - "~>"
|
200
200
|
- !ruby/object:Gem::Version
|
201
|
-
version: 0.
|
201
|
+
version: 0.4.1
|
202
202
|
type: :runtime
|
203
203
|
prerelease: false
|
204
204
|
version_requirements: !ruby/object:Gem::Requirement
|
205
205
|
requirements:
|
206
206
|
- - "~>"
|
207
207
|
- !ruby/object:Gem::Version
|
208
|
-
version: 0.
|
209
|
-
- !ruby/object:Gem::Dependency
|
210
|
-
name: bundler
|
211
|
-
requirement: !ruby/object:Gem::Requirement
|
212
|
-
requirements:
|
213
|
-
- - "~>"
|
214
|
-
- !ruby/object:Gem::Version
|
215
|
-
version: '1.10'
|
216
|
-
type: :development
|
217
|
-
prerelease: false
|
218
|
-
version_requirements: !ruby/object:Gem::Requirement
|
219
|
-
requirements:
|
220
|
-
- - "~>"
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
version: '1.10'
|
208
|
+
version: 0.4.1
|
223
209
|
- !ruby/object:Gem::Dependency
|
224
210
|
name: devtools
|
225
211
|
requirement: !ruby/object:Gem::Requirement
|
226
212
|
requirements:
|
227
213
|
- - "~>"
|
228
214
|
- !ruby/object:Gem::Version
|
229
|
-
version: 0.1.
|
215
|
+
version: 0.1.22
|
230
216
|
type: :development
|
231
217
|
prerelease: false
|
232
218
|
version_requirements: !ruby/object:Gem::Requirement
|
233
219
|
requirements:
|
234
220
|
- - "~>"
|
235
221
|
- !ruby/object:Gem::Version
|
236
|
-
version: 0.1.
|
222
|
+
version: 0.1.22
|
237
223
|
- !ruby/object:Gem::Dependency
|
238
224
|
name: parallel
|
239
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -272,8 +258,6 @@ files:
|
|
272
258
|
- Rakefile
|
273
259
|
- bin/mutant
|
274
260
|
- config/devtools.yml
|
275
|
-
- config/flay.yml
|
276
|
-
- config/flog.yml
|
277
261
|
- config/reek.yml
|
278
262
|
- config/rubocop.yml
|
279
263
|
- config/triage.yml
|
@@ -367,6 +351,7 @@ files:
|
|
367
351
|
- lib/mutant/mutator/node/dsym.rb
|
368
352
|
- lib/mutant/mutator/node/generic.rb
|
369
353
|
- lib/mutant/mutator/node/if.rb
|
354
|
+
- lib/mutant/mutator/node/index.rb
|
370
355
|
- lib/mutant/mutator/node/kwbegin.rb
|
371
356
|
- lib/mutant/mutator/node/literal.rb
|
372
357
|
- lib/mutant/mutator/node/literal/array.rb
|
@@ -390,6 +375,7 @@ files:
|
|
390
375
|
- lib/mutant/mutator/node/nthref.rb
|
391
376
|
- lib/mutant/mutator/node/op_asgn.rb
|
392
377
|
- lib/mutant/mutator/node/or_asgn.rb
|
378
|
+
- lib/mutant/mutator/node/procarg_zero.rb
|
393
379
|
- lib/mutant/mutator/node/regexp.rb
|
394
380
|
- lib/mutant/mutator/node/regexp/alternation_meta.rb
|
395
381
|
- lib/mutant/mutator/node/regexp/capture_group.rb
|
@@ -405,7 +391,6 @@ files:
|
|
405
391
|
- lib/mutant/mutator/node/send/attribute_assignment.rb
|
406
392
|
- lib/mutant/mutator/node/send/binary.rb
|
407
393
|
- lib/mutant/mutator/node/send/conditional.rb
|
408
|
-
- lib/mutant/mutator/node/send/index.rb
|
409
394
|
- lib/mutant/mutator/node/splat.rb
|
410
395
|
- lib/mutant/mutator/node/super.rb
|
411
396
|
- lib/mutant/mutator/node/when.rb
|
@@ -483,12 +468,15 @@ files:
|
|
483
468
|
- meta/gvasgn.rb
|
484
469
|
- meta/hash.rb
|
485
470
|
- meta/if.rb
|
471
|
+
- meta/index.rb
|
472
|
+
- meta/indexasgn.rb
|
486
473
|
- meta/int.rb
|
487
474
|
- meta/ivar.rb
|
488
475
|
- meta/ivasgn.rb
|
489
476
|
- meta/kwarg.rb
|
490
477
|
- meta/kwbegin.rb
|
491
478
|
- meta/kwoptarg.rb
|
479
|
+
- meta/lambda.rb
|
492
480
|
- meta/lvar.rb
|
493
481
|
- meta/lvasgn.rb
|
494
482
|
- meta/masgn.rb
|
@@ -671,7 +659,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
671
659
|
version: '0'
|
672
660
|
requirements: []
|
673
661
|
rubyforge_project:
|
674
|
-
rubygems_version: 2.7.
|
662
|
+
rubygems_version: 2.7.6
|
675
663
|
signing_key:
|
676
664
|
specification_version: 4
|
677
665
|
summary: Mutation testing tool for ruby under MRI and Rubinius
|
data/config/flay.yml
DELETED
data/config/flog.yml
DELETED