mutant 0.9.13 → 0.9.14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/mutant.rb +1 -2
- 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/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/subject/method/instance.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- metadata +6 -7
- data/lib/mutant/mutator/node/dsym.rb +0 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3e92dbf6cbb84cf8d3d5354fc5994cb1ad7cb1fb1364b1927aa89abeedcd0cef
|
4
|
+
data.tar.gz: 5c49178b6766424d6ded707a100ebad86cf9c5403a53b2c2c750baf69b4d636f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e786a6ed55abf722515f3b4b9c08200dac35557e48c27430ae5683471ededf67d1fcb17ff4e5f57f1881765d10f3a8b00ef2993f163a1cceb93531d4b75a37e3
|
7
|
+
data.tar.gz: 2a5840a2ecc0ca7c9c6156e8c4596b21808aaf8418ecf134fff9ada56a6c20e94b5ece60a0ebf0b321f1ed51ff0e5c92d26069bcb9473f61276973c46780eb5d
|
data/lib/mutant.rb
CHANGED
@@ -90,8 +90,7 @@ require 'mutant/mutator/node/arguments'
|
|
90
90
|
require 'mutant/mutator/node/begin'
|
91
91
|
require 'mutant/mutator/node/binary'
|
92
92
|
require 'mutant/mutator/node/const'
|
93
|
-
require 'mutant/mutator/node/
|
94
|
-
require 'mutant/mutator/node/dsym'
|
93
|
+
require 'mutant/mutator/node/dynamic_literal'
|
95
94
|
require 'mutant/mutator/node/kwbegin'
|
96
95
|
require 'mutant/mutator/node/named_value/access'
|
97
96
|
require 'mutant/mutator/node/named_value/constant_assignment'
|
data/lib/mutant/meta/example.rb
CHANGED
@@ -3,7 +3,19 @@
|
|
3
3
|
module Mutant
|
4
4
|
module Meta
|
5
5
|
class Example
|
6
|
-
include Adamantium
|
6
|
+
include Adamantium
|
7
|
+
include Anima.new(
|
8
|
+
:expected,
|
9
|
+
:file,
|
10
|
+
:lvars,
|
11
|
+
:node,
|
12
|
+
:original_source,
|
13
|
+
:types
|
14
|
+
)
|
15
|
+
|
16
|
+
class Expected
|
17
|
+
include Anima.new(:original_source, :node)
|
18
|
+
end
|
7
19
|
|
8
20
|
# Verification instance for example
|
9
21
|
#
|
@@ -13,13 +25,13 @@ module Mutant
|
|
13
25
|
end
|
14
26
|
memoize :verification
|
15
27
|
|
16
|
-
#
|
28
|
+
# Original source as generated by unparser
|
17
29
|
#
|
18
30
|
# @return [String]
|
19
|
-
def
|
31
|
+
def original_source_generated
|
20
32
|
Unparser.unparse(node)
|
21
33
|
end
|
22
|
-
memoize :
|
34
|
+
memoize :original_source_generated
|
23
35
|
|
24
36
|
# Generated mutations on example source
|
25
37
|
#
|
@@ -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
|
@@ -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/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.9.
|
4
|
+
version: 0.9.14
|
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-10-
|
11
|
+
date: 2020-10-16 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.2
|
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.2
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: variable
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -356,8 +356,7 @@ files:
|
|
356
356
|
- lib/mutant/mutator/node/const.rb
|
357
357
|
- lib/mutant/mutator/node/define.rb
|
358
358
|
- lib/mutant/mutator/node/defined.rb
|
359
|
-
- lib/mutant/mutator/node/
|
360
|
-
- lib/mutant/mutator/node/dsym.rb
|
359
|
+
- lib/mutant/mutator/node/dynamic_literal.rb
|
361
360
|
- lib/mutant/mutator/node/generic.rb
|
362
361
|
- lib/mutant/mutator/node/if.rb
|
363
362
|
- lib/mutant/mutator/node/index.rb
|
@@ -468,7 +467,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
468
467
|
- !ruby/object:Gem::Version
|
469
468
|
version: '0'
|
470
469
|
requirements: []
|
471
|
-
rubygems_version: 3.1.
|
470
|
+
rubygems_version: 3.1.4
|
472
471
|
signing_key:
|
473
472
|
specification_version: 4
|
474
473
|
summary: ''
|
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
|
7
|
-
# Dsym mutator
|
8
|
-
class Dsym < Generic
|
9
|
-
|
10
|
-
handle(:dsym)
|
11
|
-
|
12
|
-
private
|
13
|
-
|
14
|
-
def dispatch
|
15
|
-
super()
|
16
|
-
emit_singletons
|
17
|
-
end
|
18
|
-
|
19
|
-
end # Dsym
|
20
|
-
end # Node
|
21
|
-
end # Mutator
|
22
|
-
end # Mutant
|