mutant 0.11.3 → 0.11.6
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/lib/mutant/ast/regexp/transformer.rb +2 -2
- data/lib/mutant/cli/command/environment/run.rb +5 -22
- data/lib/mutant/cli/command.rb +2 -2
- data/lib/mutant/env.rb +6 -7
- data/lib/mutant/license/subscription/opensource.rb +1 -1
- data/lib/mutant/loader.rb +4 -13
- data/lib/mutant/matcher/config.rb +2 -3
- data/lib/mutant/matcher/method/instance.rb +10 -0
- data/lib/mutant/matcher/method.rb +27 -3
- data/lib/mutant/matcher/methods.rb +3 -1
- data/lib/mutant/mutation.rb +5 -2
- data/lib/mutant/mutator/node/arguments.rb +26 -5
- data/lib/mutant/mutator/node/block_pass.rb +1 -0
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +3 -1
- data/lib/mutant/mutator/node/when.rb +1 -1
- data/lib/mutant/repository/diff.rb +1 -1
- data/lib/mutant/subject/method/instance.rb +5 -0
- data/lib/mutant/subject/method/singleton.rb +5 -0
- data/lib/mutant/subject/method.rb +1 -0
- data/lib/mutant/subject.rb +7 -0
- data/lib/mutant/transform.rb +1 -2
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +0 -3
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 945d6584e161b704f52d2f1efc3b6a78df03cc0f6b48d52f157bf47720623725
|
4
|
+
data.tar.gz: 7a507de1188d5d8a89740730d827c89f818dee72b844f3bccfa97264d1c1e266
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f37bb36a48e29385936390ebd92790051871b6ee9b5fe053c1249815ab4432db1dbe7633e236d5bf40c04a488c1f0288bca9e29b8282f7c8a4bd2bfe0da5ee15
|
7
|
+
data.tar.gz: 281fc2061663198b9676c1000793104c7bb52fed3f4892b02419bd7a7aaf2a7168f23fb1c7ba0653710900cd7bf2637de99998da37b87cac1ca021a2dd10b0d8
|
@@ -110,9 +110,9 @@ module Mutant
|
|
110
110
|
#
|
111
111
|
# @return [Table]
|
112
112
|
def self.create(*rows)
|
113
|
-
table = rows.
|
113
|
+
table = rows.to_h do |ast_type, token, klass|
|
114
114
|
[ast_type, Mapping.new(::Regexp::Token.new(*token), klass)]
|
115
|
-
end
|
115
|
+
end
|
116
116
|
|
117
117
|
new(table)
|
118
118
|
end
|
@@ -7,13 +7,13 @@ module Mutant
|
|
7
7
|
class Run < self
|
8
8
|
NAME = 'run'
|
9
9
|
SHORT_DESCRIPTION = 'Run code analysis'
|
10
|
-
SLEEP = 60
|
11
10
|
SUBCOMMANDS = EMPTY_ARRAY
|
12
11
|
|
13
12
|
UNLICENSED = <<~MESSAGE.lines.freeze
|
14
|
-
|
15
|
-
|
16
|
-
See https://github.com/mbj/mutant#licensing
|
13
|
+
You are using mutant unlicensed.
|
14
|
+
|
15
|
+
See https://github.com/mbj/mutant#licensing to aquire a license.
|
16
|
+
Note: Its free for opensource use, which is recommended for trials.
|
17
17
|
MESSAGE
|
18
18
|
|
19
19
|
NO_TESTS_MESSAGE = <<~'MESSAGE'
|
@@ -40,7 +40,7 @@ module Mutant
|
|
40
40
|
private
|
41
41
|
|
42
42
|
def action
|
43
|
-
|
43
|
+
License.call(world)
|
44
44
|
.bind { bootstrap }
|
45
45
|
.bind(&method(:validate_tests))
|
46
46
|
.bind(&Runner.public_method(:call))
|
@@ -62,23 +62,6 @@ module Mutant
|
|
62
62
|
Either::Left.new('Uncovered mutations detected, exiting nonzero!')
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
66
|
-
def soft_fail(result)
|
67
|
-
result.either(
|
68
|
-
lambda do |message|
|
69
|
-
stderr = world.stderr
|
70
|
-
stderr.puts(message)
|
71
|
-
UNLICENSED.each { |line| stderr.puts(unlicensed(line)) }
|
72
|
-
world.kernel.sleep(SLEEP)
|
73
|
-
Either::Right.new(nil)
|
74
|
-
end,
|
75
|
-
->(_subscription) { Either::Right.new(nil) }
|
76
|
-
)
|
77
|
-
end
|
78
|
-
|
79
|
-
def unlicensed(message)
|
80
|
-
"[Mutant-License-Error]: #{message}"
|
81
|
-
end
|
82
65
|
end # Run
|
83
66
|
end # Environment
|
84
67
|
end # Command
|
data/lib/mutant/cli/command.rb
CHANGED
@@ -184,9 +184,9 @@ module Mutant
|
|
184
184
|
end
|
185
185
|
|
186
186
|
def format_subcommands
|
187
|
-
commands = subcommands.
|
187
|
+
commands = subcommands.to_h do |subcommand|
|
188
188
|
[subcommand.command_name, subcommand.short_description]
|
189
|
-
end
|
189
|
+
end
|
190
190
|
|
191
191
|
width = commands.each_key.map(&:length).max
|
192
192
|
|
data/lib/mutant/env.rb
CHANGED
@@ -68,9 +68,9 @@ module Mutant
|
|
68
68
|
#
|
69
69
|
# @return Hash{Mutation => Enumerable<Test>}
|
70
70
|
def selections
|
71
|
-
subjects.
|
71
|
+
subjects.to_h do |subject|
|
72
72
|
[subject, selector.call(subject)]
|
73
|
-
end
|
73
|
+
end
|
74
74
|
end
|
75
75
|
memoize :selections
|
76
76
|
|
@@ -142,11 +142,10 @@ module Mutant
|
|
142
142
|
result = mutation.insert(world.kernel)
|
143
143
|
hooks.run(:mutation_insert_post, mutation)
|
144
144
|
|
145
|
-
|
146
|
-
Result::Test::VoidValue.instance
|
147
|
-
|
148
|
-
|
149
|
-
end
|
145
|
+
result.either(
|
146
|
+
->(_) { Result::Test::VoidValue.instance },
|
147
|
+
->(_) { integration.call(tests) }
|
148
|
+
)
|
150
149
|
end
|
151
150
|
end
|
152
151
|
|
data/lib/mutant/loader.rb
CHANGED
@@ -9,17 +9,8 @@ module Mutant
|
|
9
9
|
|
10
10
|
private_constant(*constants(false))
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# Vale returned on successful load
|
16
|
-
class Success < self
|
17
|
-
end # Success
|
18
|
-
|
19
|
-
# Vale returned on MRI detecting void value expressions
|
20
|
-
class VoidValue < self
|
21
|
-
end # VoidValue
|
22
|
-
end # Result
|
12
|
+
VOID_VALUE = Either::Left.new(nil)
|
13
|
+
SUCCESS = Either::Right.new(nil)
|
23
14
|
|
24
15
|
# Call loader
|
25
16
|
#
|
@@ -45,12 +36,12 @@ module Mutant
|
|
45
36
|
rescue SyntaxError => exception
|
46
37
|
# rubocop:disable Style/GuardClause
|
47
38
|
if VOID_VALUE_REGEXP.match?(exception.message)
|
48
|
-
|
39
|
+
VOID_VALUE
|
49
40
|
else
|
50
41
|
raise
|
51
42
|
end
|
52
43
|
else
|
53
|
-
|
44
|
+
SUCCESS
|
54
45
|
end
|
55
46
|
end # Loader
|
56
47
|
end # Mutant
|
@@ -25,7 +25,7 @@ module Mutant
|
|
25
25
|
|
26
26
|
private_constant(*constants(false))
|
27
27
|
|
28
|
-
DEFAULT = new(anima.attribute_names.
|
28
|
+
DEFAULT = new(anima.attribute_names.to_h { |name| [name, []] })
|
29
29
|
|
30
30
|
expression = Transform::Block.capture(:expression) do |input|
|
31
31
|
Mutant::Config::DEFAULT.expression_parser.call(input)
|
@@ -74,8 +74,7 @@ module Mutant
|
|
74
74
|
def merge(other)
|
75
75
|
self.class.new(
|
76
76
|
to_h
|
77
|
-
.
|
78
|
-
.to_h
|
77
|
+
.to_h { |name, value| [name, value + other.public_send(name)] }
|
79
78
|
)
|
80
79
|
end
|
81
80
|
|
@@ -41,6 +41,16 @@ module Mutant
|
|
41
41
|
node.children.fetch(NAME_INDEX).equal?(method_name)
|
42
42
|
end
|
43
43
|
|
44
|
+
def visibility
|
45
|
+
if scope.private_instance_methods.include?(method_name)
|
46
|
+
:private
|
47
|
+
elsif scope.protected_instance_methods.include?(method_name)
|
48
|
+
:protected
|
49
|
+
else
|
50
|
+
:public
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
44
54
|
# Evaluator specialized for memoized instance methods
|
45
55
|
class Memoized < self
|
46
56
|
SUBJECT_CLASS = Subject::Method::Instance::Memoized
|
@@ -99,16 +99,40 @@ module Mutant
|
|
99
99
|
node = matched_node_path.last || return
|
100
100
|
|
101
101
|
self.class::SUBJECT_CLASS.new(
|
102
|
-
context:
|
103
|
-
node:
|
102
|
+
context: context,
|
103
|
+
node: node,
|
104
|
+
visibility: visibility
|
104
105
|
)
|
105
106
|
end
|
106
|
-
memoize :subject
|
107
107
|
|
108
108
|
def matched_node_path
|
109
109
|
AST.find_last_path(ast, &method(:match?))
|
110
110
|
end
|
111
111
|
memoize :matched_node_path
|
112
|
+
|
113
|
+
def visibility
|
114
|
+
# This can be cleaned up once we are on >ruby-3.0
|
115
|
+
# Method#{public,private,protected}? exists there.
|
116
|
+
#
|
117
|
+
# On Ruby 3.1 this can just be:
|
118
|
+
#
|
119
|
+
# if target_method.private?
|
120
|
+
# :private
|
121
|
+
# elsif target_method.protected?
|
122
|
+
# :protected
|
123
|
+
# else
|
124
|
+
# :public
|
125
|
+
# end
|
126
|
+
#
|
127
|
+
# Change to this once 3.0 is EOL.
|
128
|
+
if scope.private_methods.include?(method_name)
|
129
|
+
:private
|
130
|
+
elsif scope.protected_methods.include?(method_name)
|
131
|
+
:protected
|
132
|
+
else
|
133
|
+
:public
|
134
|
+
end
|
135
|
+
end
|
112
136
|
end # Evaluator
|
113
137
|
|
114
138
|
private_constant(*constants(false))
|
data/lib/mutant/mutation.rb
CHANGED
@@ -7,7 +7,7 @@ module Mutant
|
|
7
7
|
include Concord::Public.new(:subject, :node)
|
8
8
|
|
9
9
|
CODE_DELIMITER = "\0"
|
10
|
-
CODE_RANGE = (
|
10
|
+
CODE_RANGE = (..4).freeze
|
11
11
|
|
12
12
|
# Mutation identification code
|
13
13
|
#
|
@@ -69,7 +69,10 @@ module Mutant
|
|
69
69
|
kernel: kernel,
|
70
70
|
source: monkeypatch,
|
71
71
|
subject: subject
|
72
|
-
)
|
72
|
+
).fmap do
|
73
|
+
subject.post_insert
|
74
|
+
nil
|
75
|
+
end
|
73
76
|
end
|
74
77
|
|
75
78
|
# Rendered mutation diff
|
@@ -6,6 +6,8 @@ module Mutant
|
|
6
6
|
# Mutator for arguments node
|
7
7
|
class Arguments < self
|
8
8
|
|
9
|
+
ANONYMOUS_BLOCKARG_PRED = ::Parser::AST::Node.new(:blockarg, [nil]).method(:eql?)
|
10
|
+
|
9
11
|
handle(:args)
|
10
12
|
|
11
13
|
private
|
@@ -17,15 +19,34 @@ module Mutant
|
|
17
19
|
end
|
18
20
|
|
19
21
|
def emit_argument_presence
|
20
|
-
emit_type
|
22
|
+
emit_type unless removed_block_arg?(EMPTY_ARRAY) || forward_arg?
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
children.each_with_index do |removed, index|
|
25
|
+
new_arguments = children.dup
|
26
|
+
new_arguments.delete_at(index)
|
27
|
+
unless n_forward_arg?(removed) || removed_block_arg?(new_arguments) || only_mlhs?(new_arguments)
|
28
|
+
emit_type(*new_arguments)
|
25
29
|
end
|
26
30
|
end
|
27
31
|
end
|
28
32
|
|
33
|
+
def only_mlhs?(new_arguments)
|
34
|
+
new_arguments.one? && n_mlhs?(new_arguments.first)
|
35
|
+
end
|
36
|
+
|
37
|
+
def forward_arg?
|
38
|
+
children.last && n_forward_arg?(children.last)
|
39
|
+
end
|
40
|
+
|
41
|
+
def removed_block_arg?(new_arguments)
|
42
|
+
anonymous_block_arg? && new_arguments.none?(&ANONYMOUS_BLOCKARG_PRED)
|
43
|
+
end
|
44
|
+
|
45
|
+
def anonymous_block_arg?
|
46
|
+
children.any?(&ANONYMOUS_BLOCKARG_PRED)
|
47
|
+
end
|
48
|
+
memoize :anonymous_block_arg?
|
49
|
+
|
29
50
|
def emit_argument_mutations
|
30
51
|
children.each_with_index do |child, index|
|
31
52
|
Mutator.mutate(child).each do |mutant|
|
@@ -36,7 +57,7 @@ module Mutant
|
|
36
57
|
end
|
37
58
|
|
38
59
|
def invalid_argument_replacement?(mutant, index)
|
39
|
-
n_arg?(mutant) && children[
|
60
|
+
n_arg?(mutant) && children[...index].any?(&method(:n_optarg?))
|
40
61
|
end
|
41
62
|
|
42
63
|
def emit_mlhs_expansion
|
@@ -241,7 +241,9 @@ module Mutant
|
|
241
241
|
|
242
242
|
argument = Mutant::Util.one(arguments)
|
243
243
|
|
244
|
-
|
244
|
+
return if n_kwargs?(argument) || n_forwarded_args?(argument)
|
245
|
+
|
246
|
+
emit_propagation(argument)
|
245
247
|
end
|
246
248
|
|
247
249
|
def mutate_receiver
|
data/lib/mutant/subject.rb
CHANGED
data/lib/mutant/transform.rb
CHANGED
@@ -351,7 +351,7 @@ module Mutant
|
|
351
351
|
def transform_keys(keys, input)
|
352
352
|
success(
|
353
353
|
keys
|
354
|
-
.
|
354
|
+
.to_h do |key|
|
355
355
|
[
|
356
356
|
key.value,
|
357
357
|
coerce_key(key, input).from_right do |error|
|
@@ -359,7 +359,6 @@ module Mutant
|
|
359
359
|
end
|
360
360
|
]
|
361
361
|
end
|
362
|
-
.to_h
|
363
362
|
)
|
364
363
|
end
|
365
364
|
# rubocop:enable Metrics/MethodLength
|
data/lib/mutant/version.rb
CHANGED
data/lib/mutant/zombifier.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.11.
|
4
|
+
version: 0.11.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-04-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: diff-lcs
|
@@ -368,7 +368,8 @@ files:
|
|
368
368
|
homepage: https://github.com/mbj/mutant
|
369
369
|
licenses:
|
370
370
|
- Nonstandard
|
371
|
-
metadata:
|
371
|
+
metadata:
|
372
|
+
rubygems_mfa_required: 'true'
|
372
373
|
post_install_message:
|
373
374
|
rdoc_options: []
|
374
375
|
require_paths:
|
@@ -377,7 +378,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
377
378
|
requirements:
|
378
379
|
- - ">="
|
379
380
|
- !ruby/object:Gem::Version
|
380
|
-
version: '2.
|
381
|
+
version: '2.7'
|
381
382
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
382
383
|
requirements:
|
383
384
|
- - ">="
|