mutant 0.9.13 → 0.10.3
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of mutant might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/bin/mutant +16 -11
- data/lib/mutant.rb +7 -4
- data/lib/mutant/cli.rb +8 -167
- data/lib/mutant/cli/command.rb +196 -0
- data/lib/mutant/cli/command/root.rb +13 -0
- data/lib/mutant/cli/command/run.rb +151 -0
- data/lib/mutant/cli/command/subscription.rb +54 -0
- data/lib/mutant/expression.rb +0 -1
- data/lib/mutant/license.rb +9 -35
- data/lib/mutant/license/subscription.rb +31 -9
- data/lib/mutant/license/subscription/commercial.rb +2 -4
- data/lib/mutant/license/subscription/opensource.rb +8 -7
- data/lib/mutant/meta/example.rb +16 -4
- data/lib/mutant/meta/example/dsl.rb +33 -16
- data/lib/mutant/meta/example/verification.rb +70 -28
- data/lib/mutant/mutator/node.rb +2 -2
- data/lib/mutant/mutator/node/{dstr.rb → dynamic_literal.rb} +7 -5
- data/lib/mutant/mutator/node/index.rb +4 -4
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +1 -1
- data/lib/mutant/mutator/node/op_asgn.rb +15 -1
- data/lib/mutant/mutator/node/send.rb +1 -1
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -0
- data/lib/mutant/selector/expression.rb +3 -1
- data/lib/mutant/subject/method/instance.rb +1 -1
- data/lib/mutant/test.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- metadata +15 -13
- data/lib/mutant/minitest/coverage.rb +0 -53
- data/lib/mutant/mutator/node/dsym.rb +0 -22
@@ -25,10 +25,11 @@ module Mutant
|
|
25
25
|
#
|
26
26
|
# @return [undefined]
|
27
27
|
def initialize(file, types)
|
28
|
+
@expected = []
|
28
29
|
@file = file
|
30
|
+
@lvars = []
|
31
|
+
@source = nil
|
29
32
|
@types = types
|
30
|
-
@node = nil
|
31
|
-
@expected = []
|
32
33
|
end
|
33
34
|
|
34
35
|
# Example captured by DSL
|
@@ -38,28 +39,41 @@ module Mutant
|
|
38
39
|
# @raise [RuntimeError]
|
39
40
|
# in case example cannot be build
|
40
41
|
def example
|
41
|
-
fail 'source not defined' unless @
|
42
|
+
fail 'source not defined' unless @source
|
42
43
|
Example.new(
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
44
|
+
expected: @expected,
|
45
|
+
file: @file,
|
46
|
+
lvars: @lvars,
|
47
|
+
node: @node,
|
48
|
+
original_source: @source,
|
49
|
+
types: @types
|
47
50
|
)
|
48
51
|
end
|
49
52
|
|
53
|
+
# Declare a local variable
|
54
|
+
#
|
55
|
+
# @param [Symbol]
|
56
|
+
def declare_lvar(name)
|
57
|
+
@lvars << name
|
58
|
+
end
|
59
|
+
|
50
60
|
private
|
51
61
|
|
52
62
|
def source(input)
|
53
|
-
fail 'source already defined' if @
|
54
|
-
|
63
|
+
fail 'source already defined' if @source
|
64
|
+
|
65
|
+
@source = input
|
66
|
+
@node = node(input)
|
55
67
|
end
|
56
68
|
|
57
69
|
def mutation(input)
|
58
|
-
|
59
|
-
|
70
|
+
expected = Expected.new(original_source: input, node: node(input))
|
71
|
+
|
72
|
+
if @expected.include?(expected)
|
60
73
|
fail "Mutation for input: #{input.inspect} is already expected"
|
61
74
|
end
|
62
|
-
|
75
|
+
|
76
|
+
@expected << expected
|
63
77
|
end
|
64
78
|
|
65
79
|
def singleton_mutations
|
@@ -70,14 +84,17 @@ module Mutant
|
|
70
84
|
def node(input)
|
71
85
|
case input
|
72
86
|
when String
|
73
|
-
|
74
|
-
when ::Parser::AST::Node
|
75
|
-
input
|
87
|
+
parser.parse(Unparser.buffer(input))
|
76
88
|
else
|
77
|
-
fail "
|
89
|
+
fail "Unsupported input: #{input.inspect}"
|
78
90
|
end
|
79
91
|
end
|
80
92
|
|
93
|
+
def parser
|
94
|
+
Unparser.parser.tap do |parser|
|
95
|
+
@lvars.each(&parser.static_env.public_method(:declare))
|
96
|
+
end
|
97
|
+
end
|
81
98
|
end # DSL
|
82
99
|
end # Example
|
83
100
|
end # Meta
|
@@ -11,54 +11,96 @@ module Mutant
|
|
11
11
|
#
|
12
12
|
# @return [Boolean]
|
13
13
|
def success?
|
14
|
-
[
|
14
|
+
[
|
15
|
+
original_verification,
|
16
|
+
invalid,
|
17
|
+
missing,
|
18
|
+
no_diffs,
|
19
|
+
unexpected
|
20
|
+
].all?(&:empty?)
|
15
21
|
end
|
16
22
|
memoize :success?
|
17
23
|
|
18
|
-
# Error report
|
19
|
-
#
|
20
|
-
# @return [String]
|
21
24
|
def error_report
|
22
|
-
|
23
|
-
|
24
|
-
YAML.dump(
|
25
|
-
'file' => example.file,
|
26
|
-
'original_ast' => example.node.inspect,
|
27
|
-
'original_source' => example.source,
|
28
|
-
'missing' => format_mutations(missing),
|
29
|
-
'unexpected' => format_mutations(unexpected),
|
30
|
-
'invalid_syntax' => format_mutations(invalid_syntax),
|
31
|
-
'no_diff' => no_diff_report
|
32
|
-
)
|
25
|
+
reports.join("\n")
|
33
26
|
end
|
34
|
-
memoize :error_report
|
35
27
|
|
36
28
|
private
|
37
29
|
|
30
|
+
def reports
|
31
|
+
reports = [example.file]
|
32
|
+
reports.concat(original)
|
33
|
+
reports.concat(original_verification)
|
34
|
+
reports.concat(make_report('Missing mutations:', missing))
|
35
|
+
reports.concat(make_report('Unexpected mutations:', unexpected))
|
36
|
+
reports.concat(make_report('No-Diff mutations:', no_diffs))
|
37
|
+
reports.concat(invalid)
|
38
|
+
end
|
39
|
+
|
40
|
+
def make_report(label, mutations)
|
41
|
+
if mutations.any?
|
42
|
+
[label, mutations.map(&method(:report_mutation))]
|
43
|
+
else
|
44
|
+
[]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def report_mutation(mutation)
|
49
|
+
[
|
50
|
+
mutation.node.inspect,
|
51
|
+
mutation.source
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
def original
|
56
|
+
[
|
57
|
+
'Original:',
|
58
|
+
example.node,
|
59
|
+
example.original_source
|
60
|
+
]
|
61
|
+
end
|
62
|
+
|
63
|
+
def original_verification
|
64
|
+
validation = Unparser::Validation.from_string(example.original_source)
|
65
|
+
if validation.success?
|
66
|
+
[]
|
67
|
+
else
|
68
|
+
[
|
69
|
+
prefix('[original]', validation.report)
|
70
|
+
]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def prefix(prefix, string)
|
75
|
+
string.each_line.map do |line|
|
76
|
+
"#{prefix} #{line}"
|
77
|
+
end.join
|
78
|
+
end
|
79
|
+
|
80
|
+
def invalid
|
81
|
+
mutations.each_with_object([]) do |mutation, aggregate|
|
82
|
+
validation = Unparser::Validation.from_node(mutation.node)
|
83
|
+
aggregate << prefix('[invalid-mutation]', validation.report) unless validation.success?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
memoize :invalid
|
87
|
+
|
38
88
|
def unexpected
|
39
89
|
mutations.reject do |mutation|
|
40
|
-
example.expected.
|
90
|
+
example.expected.any? { |expected| expected.node.eql?(mutation.node) }
|
41
91
|
end
|
42
92
|
end
|
43
93
|
memoize :unexpected
|
44
94
|
|
45
95
|
def missing
|
46
|
-
(example.expected - mutations.map(&:node)).map do |node|
|
47
|
-
Mutation::Evil.new(
|
96
|
+
(example.expected.map(&:node) - mutations.map(&:node)).map do |node|
|
97
|
+
Mutation::Evil.new(nil, node)
|
48
98
|
end
|
49
99
|
end
|
50
100
|
memoize :missing
|
51
101
|
|
52
|
-
def invalid_syntax
|
53
|
-
mutations.reject do |mutation|
|
54
|
-
::Parser::CurrentRuby.parse(mutation.source)
|
55
|
-
rescue ::Parser::SyntaxError # rubocop:disable Lint/SuppressedException
|
56
|
-
end
|
57
|
-
end
|
58
|
-
memoize :invalid_syntax
|
59
|
-
|
60
102
|
def no_diffs
|
61
|
-
mutations.select { |mutation| mutation.source.eql?(example.
|
103
|
+
mutations.select { |mutation| mutation.source.eql?(example.original_source_generated) }
|
62
104
|
end
|
63
105
|
memoize :no_diffs
|
64
106
|
|
data/lib/mutant/mutator/node.rb
CHANGED
@@ -75,7 +75,7 @@ module Mutant
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def emit_nil
|
78
|
-
emit(N_NIL) unless
|
78
|
+
emit(N_NIL) unless left_op_assignment?
|
79
79
|
end
|
80
80
|
|
81
81
|
def parent_node
|
@@ -86,7 +86,7 @@ module Mutant
|
|
86
86
|
parent_node&.type
|
87
87
|
end
|
88
88
|
|
89
|
-
def
|
89
|
+
def left_op_assignment?
|
90
90
|
AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
|
91
91
|
end
|
92
92
|
|
@@ -3,17 +3,19 @@
|
|
3
3
|
module Mutant
|
4
4
|
class Mutator
|
5
5
|
class Node
|
6
|
+
# Mutator for dynamic literals
|
7
|
+
class DynamicLiteral < self
|
6
8
|
|
7
|
-
|
8
|
-
class Dstr < Generic
|
9
|
-
|
10
|
-
handle(:dstr)
|
9
|
+
handle(:dstr, :dsym)
|
11
10
|
|
12
11
|
private
|
13
12
|
|
14
13
|
def dispatch
|
15
|
-
super()
|
16
14
|
emit_singletons
|
15
|
+
|
16
|
+
children.each_index do |index|
|
17
|
+
mutate_child(index, &method(:n_begin?))
|
18
|
+
end
|
17
19
|
end
|
18
20
|
|
19
21
|
end # Dstr
|
@@ -24,7 +24,7 @@ module Mutant
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def emit_send_forms
|
27
|
-
return if
|
27
|
+
return if left_op_assignment?
|
28
28
|
|
29
29
|
SEND_REPLACEMENTS.each do |selector|
|
30
30
|
emit(s(:send, receiver, selector, *indices))
|
@@ -43,7 +43,7 @@ module Mutant
|
|
43
43
|
|
44
44
|
def mutate_indices
|
45
45
|
children_indices(index_range).each do |index|
|
46
|
-
emit_propagation(children.fetch(index)) unless
|
46
|
+
emit_propagation(children.fetch(index)) unless left_op_assignment?
|
47
47
|
delete_child(index)
|
48
48
|
mutate_child(index)
|
49
49
|
end
|
@@ -77,7 +77,7 @@ module Mutant
|
|
77
77
|
def dispatch
|
78
78
|
super()
|
79
79
|
|
80
|
-
return if
|
80
|
+
return if left_op_assignment?
|
81
81
|
|
82
82
|
emit_index_read
|
83
83
|
emit(children.last)
|
@@ -89,7 +89,7 @@ module Mutant
|
|
89
89
|
end
|
90
90
|
|
91
91
|
def index_range
|
92
|
-
if
|
92
|
+
if left_op_assignment?
|
93
93
|
NO_VALUE_RANGE
|
94
94
|
else
|
95
95
|
REGULAR_RANGE
|
@@ -15,10 +15,24 @@ module Mutant
|
|
15
15
|
|
16
16
|
def dispatch
|
17
17
|
emit_singletons
|
18
|
+
|
19
|
+
left_mutations
|
20
|
+
|
21
|
+
emit_right_mutations
|
22
|
+
end
|
23
|
+
|
24
|
+
def left_mutations
|
18
25
|
emit_left_mutations do |node|
|
19
26
|
!n_self?(node)
|
20
27
|
end
|
21
|
-
|
28
|
+
|
29
|
+
emit_left_promotion if n_send?(left)
|
30
|
+
end
|
31
|
+
|
32
|
+
def emit_left_promotion
|
33
|
+
receiver = left.children.first
|
34
|
+
|
35
|
+
emit_left(s(:ivasgn, *receiver)) if n_ivar?(receiver)
|
22
36
|
end
|
23
37
|
|
24
38
|
end # OpAsgn
|
@@ -14,7 +14,9 @@ module Mutant
|
|
14
14
|
def call(subject)
|
15
15
|
subject.match_expressions.each do |match_expression|
|
16
16
|
subject_tests = integration.all_tests.select do |test|
|
17
|
-
|
17
|
+
test.expressions.any? do |test_expression|
|
18
|
+
match_expression.prefix?(test_expression)
|
19
|
+
end
|
18
20
|
end
|
19
21
|
return subject_tests if subject_tests.any?
|
20
22
|
end
|
@@ -42,7 +42,7 @@ module Mutant
|
|
42
42
|
private
|
43
43
|
|
44
44
|
def wrap_node(mutant)
|
45
|
-
s(:begin, mutant, s(:send, nil, :memoize, s(:
|
45
|
+
s(:begin, mutant, s(:send, nil, :memoize, s(:sym, name), *options))
|
46
46
|
end
|
47
47
|
|
48
48
|
# The optional AST node for adamantium memoization options
|
data/lib/mutant/test.rb
CHANGED
data/lib/mutant/version.rb
CHANGED
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.
|
4
|
+
version: 0.10.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-11-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: abstract_type
|
@@ -184,14 +184,14 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 0.
|
187
|
+
version: 0.5.3
|
188
188
|
type: :runtime
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 0.
|
194
|
+
version: 0.5.3
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: variable
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -254,28 +254,28 @@ dependencies:
|
|
254
254
|
requirements:
|
255
255
|
- - "~>"
|
256
256
|
- !ruby/object:Gem::Version
|
257
|
-
version: 1.
|
257
|
+
version: 1.3.0
|
258
258
|
type: :development
|
259
259
|
prerelease: false
|
260
260
|
version_requirements: !ruby/object:Gem::Requirement
|
261
261
|
requirements:
|
262
262
|
- - "~>"
|
263
263
|
- !ruby/object:Gem::Version
|
264
|
-
version: 1.
|
264
|
+
version: 1.3.0
|
265
265
|
- !ruby/object:Gem::Dependency
|
266
266
|
name: rubocop
|
267
267
|
requirement: !ruby/object:Gem::Requirement
|
268
268
|
requirements:
|
269
269
|
- - "~>"
|
270
270
|
- !ruby/object:Gem::Version
|
271
|
-
version:
|
271
|
+
version: '1.0'
|
272
272
|
type: :development
|
273
273
|
prerelease: false
|
274
274
|
version_requirements: !ruby/object:Gem::Requirement
|
275
275
|
requirements:
|
276
276
|
- - "~>"
|
277
277
|
- !ruby/object:Gem::Version
|
278
|
-
version:
|
278
|
+
version: '1.0'
|
279
279
|
description: Mutation Testing for Ruby.
|
280
280
|
email:
|
281
281
|
- mbj@schirp-dso.com
|
@@ -303,6 +303,10 @@ files:
|
|
303
303
|
- lib/mutant/ast/types.rb
|
304
304
|
- lib/mutant/bootstrap.rb
|
305
305
|
- lib/mutant/cli.rb
|
306
|
+
- lib/mutant/cli/command.rb
|
307
|
+
- lib/mutant/cli/command/root.rb
|
308
|
+
- lib/mutant/cli/command/run.rb
|
309
|
+
- lib/mutant/cli/command/subscription.rb
|
306
310
|
- lib/mutant/config.rb
|
307
311
|
- lib/mutant/context.rb
|
308
312
|
- lib/mutant/env.rb
|
@@ -338,7 +342,6 @@ files:
|
|
338
342
|
- lib/mutant/meta/example.rb
|
339
343
|
- lib/mutant/meta/example/dsl.rb
|
340
344
|
- lib/mutant/meta/example/verification.rb
|
341
|
-
- lib/mutant/minitest/coverage.rb
|
342
345
|
- lib/mutant/mutation.rb
|
343
346
|
- lib/mutant/mutator.rb
|
344
347
|
- lib/mutant/mutator/node.rb
|
@@ -356,8 +359,7 @@ files:
|
|
356
359
|
- lib/mutant/mutator/node/const.rb
|
357
360
|
- lib/mutant/mutator/node/define.rb
|
358
361
|
- lib/mutant/mutator/node/defined.rb
|
359
|
-
- lib/mutant/mutator/node/
|
360
|
-
- lib/mutant/mutator/node/dsym.rb
|
362
|
+
- lib/mutant/mutator/node/dynamic_literal.rb
|
361
363
|
- lib/mutant/mutator/node/generic.rb
|
362
364
|
- lib/mutant/mutator/node/if.rb
|
363
365
|
- lib/mutant/mutator/node/index.rb
|
@@ -461,14 +463,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
461
463
|
requirements:
|
462
464
|
- - ">="
|
463
465
|
- !ruby/object:Gem::Version
|
464
|
-
version: '
|
466
|
+
version: '2.5'
|
465
467
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
466
468
|
requirements:
|
467
469
|
- - ">="
|
468
470
|
- !ruby/object:Gem::Version
|
469
471
|
version: '0'
|
470
472
|
requirements: []
|
471
|
-
rubygems_version: 3.1.
|
473
|
+
rubygems_version: 3.1.4
|
472
474
|
signing_key:
|
473
475
|
specification_version: 4
|
474
476
|
summary: ''
|