mutant 0.13.5 → 0.14.1
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/VERSION +1 -0
- data/bin/mutant +6 -59
- data/bin/mutant-ruby +64 -0
- data/lib/mutant/ast/node_predicates.rb +1 -1
- data/lib/mutant/bootstrap.rb +3 -5
- data/lib/mutant/matcher/methods.rb +9 -20
- data/lib/mutant/mutation/operators.rb +1 -1
- data/lib/mutant/mutator/node/named_value/access.rb +1 -25
- data/lib/mutant/parallel/connection.rb +12 -9
- data/lib/mutant/range.rb +1 -1
- data/lib/mutant/version.rb +17 -1
- metadata +10 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8d3a480fb26d943cb4a6b83edab4a59c8f82e887af44f2915d713187f3a1de52
|
|
4
|
+
data.tar.gz: fa67cd60285d710dea30b5de41d241f565b4fa1e199d957c05b2e250f3b4a71d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 73587288bb7e4d7c940e5fb2ed4d06c3d18c2c0e13a29e453014d2034bb84018c17b43bb6419faa51aed03363458343a83f73a016a13da21be5faea77b168b9b
|
|
7
|
+
data.tar.gz: fb6bd3cc6bd882b2fba0bf576de3076371d9f83711c13ea8bc88d520e36ebae516f3d618316c89092c78e4bb857018404512cf1c88d0cd52631145ca8a754c60
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.14.1
|
data/bin/mutant
CHANGED
|
@@ -1,64 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
# Dispatcher that selects between mutant-ruby and mutant-rust
|
|
5
|
+
# based on MUTANT_RUST environment variable.
|
|
6
|
+
#
|
|
7
|
+
# See RUST.md for documentation.
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
effective_status = status ? status + 128 : 128
|
|
10
|
-
exit! effective_status
|
|
11
|
-
end
|
|
9
|
+
fail 'MUTANT_RUST=1 is not yet supported via gem installation' if ENV['MUTANT_RUST']
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
WORLD.record(:cli_parse) do
|
|
16
|
-
CLI.parse(
|
|
17
|
-
arguments: ARGV,
|
|
18
|
-
world: Mutant::WORLD
|
|
19
|
-
)
|
|
20
|
-
end.either(
|
|
21
|
-
->(message) { Mutant::WORLD.stderr.puts(message); Kernel.exit(false) },
|
|
22
|
-
# rubocop:disable Metrics/BlockLength
|
|
23
|
-
lambda do |command|
|
|
24
|
-
if command.zombie?
|
|
25
|
-
command = WORLD.record(:zombify) do
|
|
26
|
-
$stderr.puts('Running mutant zombified!')
|
|
27
|
-
Zombifier.call(
|
|
28
|
-
namespace: :Zombie,
|
|
29
|
-
load_path: $LOAD_PATH,
|
|
30
|
-
kernel: Kernel,
|
|
31
|
-
pathname: Pathname,
|
|
32
|
-
require_highjack: RequireHighjack
|
|
33
|
-
.public_method(:call)
|
|
34
|
-
.to_proc
|
|
35
|
-
.curry
|
|
36
|
-
.call(Kernel),
|
|
37
|
-
root_require: 'mutant',
|
|
38
|
-
includes: %w[
|
|
39
|
-
adamantium
|
|
40
|
-
anima
|
|
41
|
-
concord
|
|
42
|
-
equalizer
|
|
43
|
-
mprelude
|
|
44
|
-
mutant
|
|
45
|
-
unparser
|
|
46
|
-
variable
|
|
47
|
-
]
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
Zombie::Mutant::CLI.parse(
|
|
51
|
-
arguments: ARGV,
|
|
52
|
-
world: Mutant::WORLD
|
|
53
|
-
).from_right
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
WORLD.record(:execute) { command.call }.tap do |status|
|
|
58
|
-
WORLD.recorder.print_profile(WORLD.stderr) if command.print_profile?
|
|
59
|
-
WORLD.kernel.exit(status)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
# rubocop:enable Metrics/BlockLength
|
|
63
|
-
)
|
|
64
|
-
end
|
|
11
|
+
exec('mutant-ruby', *ARGV)
|
data/bin/mutant-ruby
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
module Mutant
|
|
5
|
+
# Record executable timestamp
|
|
6
|
+
@executable_timestamp = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
7
|
+
|
|
8
|
+
trap('INT') do |status|
|
|
9
|
+
effective_status = status ? status + 128 : 128
|
|
10
|
+
exit! effective_status
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
require 'mutant'
|
|
14
|
+
|
|
15
|
+
WORLD.record(:cli_parse) do
|
|
16
|
+
CLI.parse(
|
|
17
|
+
arguments: ARGV,
|
|
18
|
+
world: Mutant::WORLD
|
|
19
|
+
)
|
|
20
|
+
end.either(
|
|
21
|
+
->(message) { Mutant::WORLD.stderr.puts(message); Kernel.exit(false) },
|
|
22
|
+
# rubocop:disable Metrics/BlockLength
|
|
23
|
+
lambda do |command|
|
|
24
|
+
if command.zombie?
|
|
25
|
+
command = WORLD.record(:zombify) do
|
|
26
|
+
$stderr.puts('Running mutant zombified!')
|
|
27
|
+
Zombifier.call(
|
|
28
|
+
namespace: :Zombie,
|
|
29
|
+
load_path: $LOAD_PATH,
|
|
30
|
+
kernel: Kernel,
|
|
31
|
+
pathname: Pathname,
|
|
32
|
+
require_highjack: RequireHighjack
|
|
33
|
+
.public_method(:call)
|
|
34
|
+
.to_proc
|
|
35
|
+
.curry
|
|
36
|
+
.call(Kernel),
|
|
37
|
+
root_require: 'mutant',
|
|
38
|
+
includes: %w[
|
|
39
|
+
adamantium
|
|
40
|
+
anima
|
|
41
|
+
concord
|
|
42
|
+
equalizer
|
|
43
|
+
mprelude
|
|
44
|
+
mutant
|
|
45
|
+
unparser
|
|
46
|
+
variable
|
|
47
|
+
]
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
Zombie::Mutant::CLI.parse(
|
|
51
|
+
arguments: ARGV,
|
|
52
|
+
world: Mutant::WORLD
|
|
53
|
+
).from_right
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
WORLD.record(:execute) { command.call }.tap do |status|
|
|
58
|
+
WORLD.recorder.print_profile(WORLD.stderr) if command.print_profile?
|
|
59
|
+
WORLD.kernel.exit(status)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
# rubocop:enable Metrics/BlockLength
|
|
63
|
+
)
|
|
64
|
+
end
|
|
@@ -6,7 +6,7 @@ module Mutant
|
|
|
6
6
|
module NodePredicates
|
|
7
7
|
|
|
8
8
|
Types::ALL.each do |type|
|
|
9
|
-
fail "method: #{type} is already defined" if
|
|
9
|
+
fail "method: #{type} is already defined" if method_defined?(type)
|
|
10
10
|
|
|
11
11
|
name = "n_#{type.to_s.chomp('?')}?"
|
|
12
12
|
|
data/lib/mutant/bootstrap.rb
CHANGED
|
@@ -73,7 +73,6 @@ module Mutant
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
# rubocop:disable Metrics/MethodLength
|
|
76
|
-
# rubocop:disable Style/MultilineBlockChain
|
|
77
76
|
def self.setup_integration(env:, mutations:, selected_subjects:)
|
|
78
77
|
env.record(__method__) do
|
|
79
78
|
hooks = env.hooks
|
|
@@ -84,14 +83,13 @@ module Mutant
|
|
|
84
83
|
mutations:,
|
|
85
84
|
selector: Selector::Expression.new(integration:),
|
|
86
85
|
subjects: selected_subjects
|
|
87
|
-
)
|
|
88
|
-
end
|
|
86
|
+
).tap { hooks.run(:setup_integration_post) }
|
|
87
|
+
end
|
|
89
88
|
end
|
|
90
89
|
end
|
|
91
90
|
private_class_method :setup_integration
|
|
92
|
-
# rubocop:enable Metrics/MethodLength
|
|
93
|
-
# rubocop:enable Style/MultilineBlockChain
|
|
94
91
|
|
|
92
|
+
# rubocop:enable Metrics/MethodLength
|
|
95
93
|
def self.load_hooks(env)
|
|
96
94
|
env.record(__method__) do
|
|
97
95
|
env.with(hooks: Hooks.load_config(env.config))
|
|
@@ -36,7 +36,7 @@ module Mutant
|
|
|
36
36
|
def methods(env)
|
|
37
37
|
candidate_names.each_with_object([]) do |name, methods|
|
|
38
38
|
method = access(env, name)
|
|
39
|
-
methods << method if method
|
|
39
|
+
methods << method if method
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
42
|
|
|
@@ -50,10 +50,8 @@ module Mutant
|
|
|
50
50
|
abstract_method :candidate_scope
|
|
51
51
|
private :candidate_scope
|
|
52
52
|
|
|
53
|
-
# Matcher for
|
|
54
|
-
class
|
|
55
|
-
MATCHER = Matcher::Method::Singleton
|
|
56
|
-
|
|
53
|
+
# Matcher for eigenclass methods
|
|
54
|
+
class Eigenclass < self
|
|
57
55
|
private
|
|
58
56
|
|
|
59
57
|
def access(_env, method_name)
|
|
@@ -63,22 +61,16 @@ module Mutant
|
|
|
63
61
|
def candidate_scope
|
|
64
62
|
scope.raw.singleton_class
|
|
65
63
|
end
|
|
64
|
+
end # Eigenclass
|
|
66
65
|
|
|
66
|
+
# Matcher for singleton methods
|
|
67
|
+
class Singleton < Eigenclass
|
|
68
|
+
MATCHER = Matcher::Method::Singleton
|
|
67
69
|
end # Singleton
|
|
68
70
|
|
|
69
71
|
# Matcher for metaclass methods
|
|
70
|
-
class Metaclass <
|
|
72
|
+
class Metaclass < Eigenclass
|
|
71
73
|
MATCHER = Matcher::Method::Metaclass
|
|
72
|
-
|
|
73
|
-
private
|
|
74
|
-
|
|
75
|
-
def access(_env, method_name)
|
|
76
|
-
scope.raw.method(method_name)
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def candidate_scope
|
|
80
|
-
scope.raw.singleton_class
|
|
81
|
-
end
|
|
82
74
|
end # Metaclass
|
|
83
75
|
|
|
84
76
|
# Matcher for instance methods
|
|
@@ -104,17 +96,14 @@ module Mutant
|
|
|
104
96
|
|
|
105
97
|
private
|
|
106
98
|
|
|
107
|
-
# rubocop:disable Lint/RescueException
|
|
108
|
-
# mutant:disable - unstable source locations under < ruby-3.2
|
|
109
99
|
def access(env, method_name)
|
|
110
100
|
candidate_scope.instance_method(method_name)
|
|
111
|
-
rescue
|
|
101
|
+
rescue => exception
|
|
112
102
|
env.warn(
|
|
113
103
|
MESSAGE % { scope:, method_name:, exception: exception.inspect }
|
|
114
104
|
)
|
|
115
105
|
nil
|
|
116
106
|
end
|
|
117
|
-
# rubocop:enable Lint/RescueException
|
|
118
107
|
|
|
119
108
|
def candidate_scope
|
|
120
109
|
scope.raw
|
|
@@ -8,7 +8,7 @@ module Mutant
|
|
|
8
8
|
# Mutation emitter to handle named value access nodes
|
|
9
9
|
class Access < Node
|
|
10
10
|
|
|
11
|
-
handle(:gvar, :cvar, :lvar, :self)
|
|
11
|
+
handle(:gvar, :cvar, :ivar, :lvar, :self)
|
|
12
12
|
|
|
13
13
|
private
|
|
14
14
|
|
|
@@ -16,30 +16,6 @@ module Mutant
|
|
|
16
16
|
emit_singletons
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
# Named value access emitter for instance variables
|
|
20
|
-
class Ivar < Access
|
|
21
|
-
NAME_RANGE = (1..-1)
|
|
22
|
-
|
|
23
|
-
handle(:ivar)
|
|
24
|
-
|
|
25
|
-
children :name
|
|
26
|
-
|
|
27
|
-
private
|
|
28
|
-
|
|
29
|
-
def dispatch
|
|
30
|
-
emit_attribute_read
|
|
31
|
-
super
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def emit_attribute_read
|
|
35
|
-
emit(s(:send, nil, attribute_name))
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
def attribute_name
|
|
39
|
-
name.slice(NAME_RANGE).to_sym
|
|
40
|
-
end
|
|
41
|
-
end # Ivar
|
|
42
|
-
|
|
43
19
|
end # Access
|
|
44
20
|
end # NamedValue
|
|
45
21
|
end # Node
|
|
@@ -10,6 +10,7 @@ module Mutant
|
|
|
10
10
|
HEADER_FORMAT = 'N'
|
|
11
11
|
HEADER_SIZE = 4
|
|
12
12
|
MAX_BYTES = (2**32).pred
|
|
13
|
+
MAX_LOG_CHUNK = 4096
|
|
13
14
|
|
|
14
15
|
class Reader
|
|
15
16
|
include Anima.new(:deadline, :io, :marshal, :response_reader, :log_reader)
|
|
@@ -86,10 +87,10 @@ module Mutant
|
|
|
86
87
|
|
|
87
88
|
def advance_result
|
|
88
89
|
if length
|
|
89
|
-
if
|
|
90
|
+
if read_result_buffer(length)
|
|
90
91
|
@results << marshal.load(@buffer)
|
|
91
92
|
end
|
|
92
|
-
elsif
|
|
93
|
+
elsif read_result_buffer(HEADER_SIZE)
|
|
93
94
|
@lengths << Util.one(@buffer.unpack(HEADER_FORMAT))
|
|
94
95
|
@buffer = +''
|
|
95
96
|
end
|
|
@@ -100,17 +101,16 @@ module Mutant
|
|
|
100
101
|
end
|
|
101
102
|
|
|
102
103
|
def advance_log
|
|
103
|
-
with_nonblock_read(io: log_reader, max_bytes:
|
|
104
|
+
while with_nonblock_read(io: log_reader, max_bytes: MAX_LOG_CHUNK, &@log.public_method(:<<))
|
|
105
|
+
end
|
|
104
106
|
end
|
|
105
107
|
|
|
106
|
-
def
|
|
108
|
+
def read_result_buffer(max_bytes)
|
|
107
109
|
with_nonblock_read(
|
|
108
110
|
io: response_reader,
|
|
109
|
-
max_bytes: max_bytes - @buffer.bytesize
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
@buffer.bytesize.equal?(max_bytes)
|
|
113
|
-
end
|
|
111
|
+
max_bytes: max_bytes - @buffer.bytesize,
|
|
112
|
+
&@buffer.public_method(:<<)
|
|
113
|
+
)
|
|
114
114
|
end
|
|
115
115
|
|
|
116
116
|
# rubocop:disable Metrics/MethodLength
|
|
@@ -123,8 +123,11 @@ module Mutant
|
|
|
123
123
|
when nil
|
|
124
124
|
@errors << EOFError
|
|
125
125
|
false
|
|
126
|
+
when :wait_readable
|
|
127
|
+
false
|
|
126
128
|
when String
|
|
127
129
|
yield chunk
|
|
130
|
+
chunk.bytesize.equal?(max_bytes)
|
|
128
131
|
else
|
|
129
132
|
fail "Unexpected nonblocking read return: #{chunk.inspect}"
|
|
130
133
|
end
|
data/lib/mutant/range.rb
CHANGED
data/lib/mutant/version.rb
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'pathname'
|
|
4
|
+
|
|
3
5
|
module Mutant
|
|
4
6
|
# Current mutant version
|
|
5
|
-
|
|
7
|
+
#
|
|
8
|
+
# See RUST.md for documentation on version loading behavior.
|
|
9
|
+
VERSION =
|
|
10
|
+
if ENV['MUTANT_RUST']
|
|
11
|
+
ENV.fetch('MUTANT_VERSION').freeze
|
|
12
|
+
else
|
|
13
|
+
Pathname
|
|
14
|
+
.new(__dir__)
|
|
15
|
+
.parent
|
|
16
|
+
.parent
|
|
17
|
+
.join('VERSION')
|
|
18
|
+
.read
|
|
19
|
+
.chomp
|
|
20
|
+
.freeze
|
|
21
|
+
end
|
|
6
22
|
end # Mutant
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mutant
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.14.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Markus Schirp
|
|
@@ -29,14 +29,14 @@ dependencies:
|
|
|
29
29
|
requirements:
|
|
30
30
|
- - "~>"
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
|
-
version: 1.15
|
|
32
|
+
version: '1.15'
|
|
33
33
|
type: :runtime
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: 1.15
|
|
39
|
+
version: '1.15'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: parser
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -71,14 +71,14 @@ dependencies:
|
|
|
71
71
|
requirements:
|
|
72
72
|
- - "~>"
|
|
73
73
|
- !ruby/object:Gem::Version
|
|
74
|
-
version: 0.
|
|
74
|
+
version: 0.6.0
|
|
75
75
|
type: :runtime
|
|
76
76
|
prerelease: false
|
|
77
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
78
78
|
requirements:
|
|
79
79
|
- - "~>"
|
|
80
80
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: 0.
|
|
81
|
+
version: 0.6.0
|
|
82
82
|
- !ruby/object:Gem::Dependency
|
|
83
83
|
name: unparser
|
|
84
84
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -127,14 +127,14 @@ dependencies:
|
|
|
127
127
|
requirements:
|
|
128
128
|
- - "~>"
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
|
-
version:
|
|
130
|
+
version: '2.0'
|
|
131
131
|
type: :development
|
|
132
132
|
prerelease: false
|
|
133
133
|
version_requirements: !ruby/object:Gem::Requirement
|
|
134
134
|
requirements:
|
|
135
135
|
- - "~>"
|
|
136
136
|
- !ruby/object:Gem::Version
|
|
137
|
-
version:
|
|
137
|
+
version: '2.0'
|
|
138
138
|
- !ruby/object:Gem::Dependency
|
|
139
139
|
name: rubocop
|
|
140
140
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -154,12 +154,15 @@ email:
|
|
|
154
154
|
- mbj@schirp-dso.com
|
|
155
155
|
executables:
|
|
156
156
|
- mutant
|
|
157
|
+
- mutant-ruby
|
|
157
158
|
extensions: []
|
|
158
159
|
extra_rdoc_files:
|
|
159
160
|
- LICENSE
|
|
160
161
|
files:
|
|
161
162
|
- LICENSE
|
|
163
|
+
- VERSION
|
|
162
164
|
- bin/mutant
|
|
165
|
+
- bin/mutant-ruby
|
|
163
166
|
- lib/mutant.rb
|
|
164
167
|
- lib/mutant/ast.rb
|
|
165
168
|
- lib/mutant/ast/find_metaclass_containing.rb
|