mutant 0.10.6 → 0.10.11
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.rb +7 -4
- data/lib/mutant/cli/command.rb +1 -1
- data/lib/mutant/cli/command/{run.rb → environment.rb} +10 -45
- data/lib/mutant/cli/command/environment/run.rb +56 -0
- data/lib/mutant/cli/command/environment/show.rb +29 -0
- data/lib/mutant/cli/command/root.rb +7 -3
- data/lib/mutant/config.rb +61 -34
- data/lib/mutant/env.rb +14 -4
- data/lib/mutant/integration.rb +16 -10
- data/lib/mutant/integration/null.rb +0 -1
- data/lib/mutant/isolation.rb +11 -48
- data/lib/mutant/isolation/fork.rb +107 -40
- data/lib/mutant/isolation/none.rb +18 -5
- data/lib/mutant/license/subscription/commercial.rb +2 -3
- data/lib/mutant/license/subscription/opensource.rb +0 -1
- data/lib/mutant/matcher/method/instance.rb +0 -2
- data/lib/mutant/mutator/node/send.rb +1 -1
- data/lib/mutant/parallel.rb +0 -1
- data/lib/mutant/parallel/worker.rb +0 -2
- data/lib/mutant/reporter/cli.rb +0 -2
- data/lib/mutant/reporter/cli/printer/config.rb +9 -5
- data/lib/mutant/reporter/cli/printer/coverage_result.rb +19 -0
- data/lib/mutant/reporter/cli/printer/env_progress.rb +2 -0
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +19 -35
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +4 -9
- data/lib/mutant/reporter/cli/printer/subject_result.rb +2 -2
- data/lib/mutant/result.rb +91 -30
- data/lib/mutant/runner/sink.rb +12 -5
- data/lib/mutant/timer.rb +60 -11
- data/lib/mutant/transform.rb +25 -21
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warnings.rb +0 -1
- data/lib/mutant/world.rb +15 -0
- metadata +6 -6
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -28
- data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -58
- data/lib/mutant/reporter/cli/printer/test_result.rb +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f812d15b5c09f8681cc6c75eb01bd00fffe412bc53397b9e13c29c7cad69db9a
|
4
|
+
data.tar.gz: 45c24afcbfbef29a50b90b81946e75391c58ecea7ac32b9545a5e7fdc22fd063
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcb16a15ec71fe5dc51d07e08b426e8dc68e2f4bad2bd47f95a19b136cd06dbefdc9be44f4a7e0723b8a9450b4b924ab2744f8be05b09fbf1d6e9774431f2e97
|
7
|
+
data.tar.gz: b9213ce07ce70908f072b23d92bd86c86492ed8f348ae2c7419ed625989a36b7b2d1e110048e14364e044790e7e086894c124f081043d989844de02adcc81684
|
data/lib/mutant.rb
CHANGED
@@ -167,8 +167,10 @@ require 'mutant/world'
|
|
167
167
|
require 'mutant/config'
|
168
168
|
require 'mutant/cli'
|
169
169
|
require 'mutant/cli/command'
|
170
|
-
require 'mutant/cli/command/run'
|
171
170
|
require 'mutant/cli/command/subscription'
|
171
|
+
require 'mutant/cli/command/environment'
|
172
|
+
require 'mutant/cli/command/environment/run'
|
173
|
+
require 'mutant/cli/command/environment/show'
|
172
174
|
require 'mutant/cli/command/root'
|
173
175
|
require 'mutant/runner'
|
174
176
|
require 'mutant/runner/sink'
|
@@ -179,16 +181,14 @@ require 'mutant/reporter/sequence'
|
|
179
181
|
require 'mutant/reporter/cli'
|
180
182
|
require 'mutant/reporter/cli/printer'
|
181
183
|
require 'mutant/reporter/cli/printer/config'
|
184
|
+
require 'mutant/reporter/cli/printer/coverage_result'
|
182
185
|
require 'mutant/reporter/cli/printer/env'
|
183
186
|
require 'mutant/reporter/cli/printer/env_progress'
|
184
187
|
require 'mutant/reporter/cli/printer/env_result'
|
185
188
|
require 'mutant/reporter/cli/printer/isolation_result'
|
186
|
-
require 'mutant/reporter/cli/printer/mutation_progress_result'
|
187
189
|
require 'mutant/reporter/cli/printer/mutation_result'
|
188
190
|
require 'mutant/reporter/cli/printer/status_progressive'
|
189
|
-
require 'mutant/reporter/cli/printer/subject_progress'
|
190
191
|
require 'mutant/reporter/cli/printer/subject_result'
|
191
|
-
require 'mutant/reporter/cli/printer/test_result'
|
192
192
|
require 'mutant/reporter/cli/format'
|
193
193
|
require 'mutant/repository'
|
194
194
|
require 'mutant/repository/diff'
|
@@ -219,12 +219,14 @@ module Mutant
|
|
219
219
|
stderr: $stderr,
|
220
220
|
stdout: $stdout,
|
221
221
|
thread: Thread,
|
222
|
+
timer: Timer.new(Process),
|
222
223
|
warnings: Warnings.new(Warning)
|
223
224
|
)
|
224
225
|
|
225
226
|
# Reopen class to initialize constant to avoid dep circle
|
226
227
|
class Config
|
227
228
|
DEFAULT = new(
|
229
|
+
coverage_criteria: Config::CoverageCriteria::DEFAULT,
|
228
230
|
expression_parser: Expression::Parser.new([
|
229
231
|
Expression::Method,
|
230
232
|
Expression::Methods,
|
@@ -237,6 +239,7 @@ module Mutant
|
|
237
239
|
isolation: Mutant::Isolation::Fork.new(WORLD),
|
238
240
|
jobs: nil,
|
239
241
|
matcher: Matcher::Config::DEFAULT,
|
242
|
+
mutation_timeout: nil,
|
240
243
|
reporter: Reporter::CLI.build(WORLD.stdout),
|
241
244
|
requires: EMPTY_ARRAY,
|
242
245
|
zombie: false
|
data/lib/mutant/cli/command.rb
CHANGED
@@ -3,10 +3,9 @@
|
|
3
3
|
module Mutant
|
4
4
|
module CLI
|
5
5
|
class Command
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
SHORT_DESCRIPTION = 'Run code analysis'
|
6
|
+
class Environment < self
|
7
|
+
NAME = 'environment'
|
8
|
+
SHORT_DESCRIPTION = 'Environment subcommands'
|
10
9
|
|
11
10
|
OPTIONS =
|
12
11
|
%i[
|
@@ -16,57 +15,21 @@ module Mutant
|
|
16
15
|
add_matcher_options
|
17
16
|
].freeze
|
18
17
|
|
19
|
-
SLEEP = 40
|
20
|
-
|
21
|
-
UNLICENSED = <<~MESSAGE.lines.freeze
|
22
|
-
Soft fail, continuing in #{SLEEP} seconds
|
23
|
-
Next major version will enforce the license
|
24
|
-
See https://github.com/mbj/mutant#licensing
|
25
|
-
MESSAGE
|
26
|
-
|
27
|
-
# Test if command needs to be executed in zombie environment
|
28
|
-
#
|
29
|
-
# @return [Bool]
|
30
|
-
def zombie?
|
31
|
-
@config.zombie
|
32
|
-
end
|
33
|
-
|
34
18
|
private
|
35
19
|
|
36
20
|
def initialize(attributes)
|
37
21
|
super(attributes)
|
38
|
-
@config = Config
|
22
|
+
@config = Config.env
|
39
23
|
end
|
40
24
|
|
41
|
-
def
|
42
|
-
|
43
|
-
.bind { Config.load_config_file(world) }
|
25
|
+
def bootstrap
|
26
|
+
Config.load_config_file(world)
|
44
27
|
.fmap(&method(:expand))
|
45
28
|
.bind { Bootstrap.apply(world, @config) }
|
46
|
-
.bind(&Runner.public_method(:apply))
|
47
|
-
.from_right { |error| world.stderr.puts(error); return false }
|
48
|
-
.success?
|
49
29
|
end
|
50
30
|
|
51
31
|
def expand(file_config)
|
52
|
-
@config =
|
53
|
-
end
|
54
|
-
|
55
|
-
def soft_fail(result)
|
56
|
-
result.either(
|
57
|
-
lambda do |message|
|
58
|
-
stderr = world.stderr
|
59
|
-
stderr.puts(message)
|
60
|
-
UNLICENSED.each { |line| stderr.puts(unlicensed(line)) }
|
61
|
-
world.kernel.sleep(SLEEP)
|
62
|
-
Either::Right.new(nil)
|
63
|
-
end,
|
64
|
-
->(_subscription) { Either::Right.new(nil) }
|
65
|
-
)
|
66
|
-
end
|
67
|
-
|
68
|
-
def unlicensed(message)
|
69
|
-
"[Mutant-License-Error]: #{message}"
|
32
|
+
@config = file_config.merge(@config)
|
70
33
|
end
|
71
34
|
|
72
35
|
def parse_remaining_arguments(arguments)
|
@@ -153,9 +116,11 @@ module Mutant
|
|
153
116
|
parser.on('-j', '--jobs NUMBER', 'Number of kill jobs. Defaults to number of processors.') do |number|
|
154
117
|
set(jobs: Integer(number))
|
155
118
|
end
|
119
|
+
parser.on('-t', '--mutation-timeout NUMBER', 'Per mutation analysis timeout') do |number|
|
120
|
+
set(mutation_timeout: Float(number))
|
121
|
+
end
|
156
122
|
end
|
157
123
|
end # Run
|
158
|
-
# rubocop:enable Metrics/ClassLength
|
159
124
|
end # Command
|
160
125
|
end # CLI
|
161
126
|
end # Mutant
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
module CLI
|
5
|
+
class Command
|
6
|
+
class Environment
|
7
|
+
class Run < self
|
8
|
+
NAME = 'run'
|
9
|
+
SHORT_DESCRIPTION = 'Run code analysis'
|
10
|
+
SLEEP = 40
|
11
|
+
SUBCOMMANDS = EMPTY_ARRAY
|
12
|
+
|
13
|
+
UNLICENSED = <<~MESSAGE.lines.freeze
|
14
|
+
Soft fail, continuing in #{SLEEP} seconds
|
15
|
+
Next major version will enforce the license
|
16
|
+
See https://github.com/mbj/mutant#licensing
|
17
|
+
MESSAGE
|
18
|
+
|
19
|
+
# Test if command needs to be executed in zombie environment
|
20
|
+
#
|
21
|
+
# @return [Bool]
|
22
|
+
def zombie?
|
23
|
+
@config.zombie
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def execute
|
29
|
+
soft_fail(License.apply(world))
|
30
|
+
.bind { bootstrap }
|
31
|
+
.bind(&Runner.public_method(:apply))
|
32
|
+
.from_right { |error| world.stderr.puts(error); return false }
|
33
|
+
.success?
|
34
|
+
end
|
35
|
+
|
36
|
+
def soft_fail(result)
|
37
|
+
result.either(
|
38
|
+
lambda do |message|
|
39
|
+
stderr = world.stderr
|
40
|
+
stderr.puts(message)
|
41
|
+
UNLICENSED.each { |line| stderr.puts(unlicensed(line)) }
|
42
|
+
world.kernel.sleep(SLEEP)
|
43
|
+
Either::Right.new(nil)
|
44
|
+
end,
|
45
|
+
->(_subscription) { Either::Right.new(nil) }
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def unlicensed(message)
|
50
|
+
"[Mutant-License-Error]: #{message}"
|
51
|
+
end
|
52
|
+
end # Run
|
53
|
+
end # Environment
|
54
|
+
end # Command
|
55
|
+
end # CLI
|
56
|
+
end # Mutant
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
module CLI
|
5
|
+
class Command
|
6
|
+
class Environment
|
7
|
+
class Show < self
|
8
|
+
NAME = 'show'
|
9
|
+
SHORT_DESCRIPTION = 'Display environment without coverage analysis'
|
10
|
+
SUBCOMMANDS = EMPTY_ARRAY
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def execute
|
15
|
+
Config.load_config_file(world)
|
16
|
+
.fmap(&method(:expand))
|
17
|
+
.bind { Bootstrap.apply(world, @config) }
|
18
|
+
.fmap(&method(:report_env))
|
19
|
+
.right?
|
20
|
+
end
|
21
|
+
|
22
|
+
def report_env(env)
|
23
|
+
env.config.reporter.start(env)
|
24
|
+
end
|
25
|
+
end # Show
|
26
|
+
end # Environment
|
27
|
+
end # Command
|
28
|
+
end # CLI
|
29
|
+
end # Mutant
|
@@ -3,11 +3,15 @@
|
|
3
3
|
module Mutant
|
4
4
|
module CLI
|
5
5
|
class Command
|
6
|
+
class Environment < self
|
7
|
+
SUBCOMMANDS = [Environment::Show].freeze
|
8
|
+
end # Environment
|
9
|
+
|
6
10
|
class Root < self
|
7
|
-
SUBCOMMANDS = [Run, Subscription].freeze
|
8
|
-
SHORT_DESCRIPTION = 'mutation testing engine main command'
|
9
11
|
NAME = 'mutant'
|
10
|
-
|
12
|
+
SHORT_DESCRIPTION = 'mutation testing engine main command'
|
13
|
+
SUBCOMMANDS = [Environment::Run, Environment, Subscription].freeze
|
14
|
+
end # Root
|
11
15
|
end # Command
|
12
16
|
end # CLI
|
13
17
|
end # Mutant
|
data/lib/mutant/config.rb
CHANGED
@@ -7,6 +7,7 @@ module Mutant
|
|
7
7
|
# to current environment is being represented by the Mutant::Env object.
|
8
8
|
class Config
|
9
9
|
include Adamantium::Flat, Anima.new(
|
10
|
+
:coverage_criteria,
|
10
11
|
:expression_parser,
|
11
12
|
:fail_fast,
|
12
13
|
:includes,
|
@@ -14,6 +15,7 @@ module Mutant
|
|
14
15
|
:isolation,
|
15
16
|
:jobs,
|
16
17
|
:matcher,
|
18
|
+
:mutation_timeout,
|
17
19
|
:reporter,
|
18
20
|
:requires,
|
19
21
|
:zombie
|
@@ -23,30 +25,6 @@ module Mutant
|
|
23
25
|
define_method(:"#{name}?") { public_send(name) }
|
24
26
|
end
|
25
27
|
|
26
|
-
boolean = Transform::Boolean.new
|
27
|
-
integer = Transform::Primitive.new(Integer)
|
28
|
-
string = Transform::Primitive.new(String)
|
29
|
-
|
30
|
-
string_array = Transform::Array.new(string)
|
31
|
-
|
32
|
-
TRANSFORM = Transform::Sequence.new(
|
33
|
-
[
|
34
|
-
Transform::Exception.new(SystemCallError, :read.to_proc),
|
35
|
-
Transform::Exception.new(YAML::SyntaxError, YAML.method(:safe_load)),
|
36
|
-
Transform::Hash.new(
|
37
|
-
optional: [
|
38
|
-
Transform::Hash::Key.new('fail_fast', boolean),
|
39
|
-
Transform::Hash::Key.new('includes', string_array),
|
40
|
-
Transform::Hash::Key.new('integration', string),
|
41
|
-
Transform::Hash::Key.new('jobs', integer),
|
42
|
-
Transform::Hash::Key.new('requires', string_array)
|
43
|
-
],
|
44
|
-
required: []
|
45
|
-
),
|
46
|
-
Transform::Hash::Symbolize.new
|
47
|
-
]
|
48
|
-
)
|
49
|
-
|
50
28
|
MORE_THAN_ONE_CONFIG_FILE = <<~'MESSAGE'
|
51
29
|
Found more than one candidate for use as implicit config file: %s
|
52
30
|
MESSAGE
|
@@ -57,6 +35,34 @@ module Mutant
|
|
57
35
|
mutant.yml
|
58
36
|
].freeze
|
59
37
|
|
38
|
+
private_constant(*constants(false))
|
39
|
+
|
40
|
+
class CoverageCriteria
|
41
|
+
include Anima.new(:process_abort, :test_result, :timeout)
|
42
|
+
|
43
|
+
DEFAULT = new(
|
44
|
+
process_abort: false,
|
45
|
+
test_result: true,
|
46
|
+
timeout: false
|
47
|
+
)
|
48
|
+
|
49
|
+
TRANSFORM =
|
50
|
+
Transform::Sequence.new(
|
51
|
+
[
|
52
|
+
Transform::Hash.new(
|
53
|
+
optional: [
|
54
|
+
Transform::Hash::Key.new('process_abort', Transform::BOOLEAN),
|
55
|
+
Transform::Hash::Key.new('test_result', Transform::BOOLEAN),
|
56
|
+
Transform::Hash::Key.new('timeout', Transform::BOOLEAN)
|
57
|
+
],
|
58
|
+
required: []
|
59
|
+
),
|
60
|
+
Transform::Hash::Symbolize.new,
|
61
|
+
->(value) { Either::Right.new(DEFAULT.with(**value)) }
|
62
|
+
]
|
63
|
+
)
|
64
|
+
end # CoverageCriteria
|
65
|
+
|
60
66
|
# Merge with other config
|
61
67
|
#
|
62
68
|
# @param [Config] other
|
@@ -64,18 +70,17 @@ module Mutant
|
|
64
70
|
# @return [Config]
|
65
71
|
def merge(other)
|
66
72
|
other.with(
|
67
|
-
fail_fast:
|
68
|
-
includes:
|
69
|
-
jobs:
|
70
|
-
integration:
|
71
|
-
|
72
|
-
|
73
|
-
|
73
|
+
fail_fast: fail_fast || other.fail_fast,
|
74
|
+
includes: includes + other.includes,
|
75
|
+
jobs: other.jobs || jobs,
|
76
|
+
integration: other.integration || integration,
|
77
|
+
mutation_timeout: other.mutation_timeout || mutation_timeout,
|
78
|
+
matcher: matcher.merge(other.matcher),
|
79
|
+
requires: requires + other.requires,
|
80
|
+
zombie: zombie || other.zombie
|
74
81
|
)
|
75
82
|
end
|
76
83
|
|
77
|
-
private_constant(*constants(false))
|
78
|
-
|
79
84
|
# Load config file
|
80
85
|
#
|
81
86
|
# @param [World] world
|
@@ -98,7 +103,7 @@ module Mutant
|
|
98
103
|
def self.load_contents(path)
|
99
104
|
Transform::Named
|
100
105
|
.new(path.to_s, TRANSFORM)
|
101
|
-
.
|
106
|
+
.call(path)
|
102
107
|
.lmap(&:compact_message)
|
103
108
|
end
|
104
109
|
private_class_method :load_contents
|
@@ -109,5 +114,27 @@ module Mutant
|
|
109
114
|
def self.env
|
110
115
|
DEFAULT.with(jobs: Etc.nprocessors)
|
111
116
|
end
|
117
|
+
|
118
|
+
TRANSFORM = Transform::Sequence.new(
|
119
|
+
[
|
120
|
+
Transform::Exception.new(SystemCallError, :read.to_proc),
|
121
|
+
Transform::Exception.new(YAML::SyntaxError, YAML.method(:safe_load)),
|
122
|
+
Transform::Hash.new(
|
123
|
+
optional: [
|
124
|
+
Transform::Hash::Key.new('coverage_criteria', CoverageCriteria::TRANSFORM),
|
125
|
+
Transform::Hash::Key.new('fail_fast', Transform::BOOLEAN),
|
126
|
+
Transform::Hash::Key.new('includes', Transform::STRING_ARRAY),
|
127
|
+
Transform::Hash::Key.new('integration', Transform::STRING),
|
128
|
+
Transform::Hash::Key.new('jobs', Transform::INTEGER),
|
129
|
+
Transform::Hash::Key.new('mutation_timeout', Transform::FLOAT),
|
130
|
+
Transform::Hash::Key.new('requires', Transform::STRING_ARRAY)
|
131
|
+
],
|
132
|
+
required: []
|
133
|
+
),
|
134
|
+
Transform::Hash::Symbolize.new
|
135
|
+
]
|
136
|
+
)
|
137
|
+
|
138
|
+
private_constant(:TRANSFORM)
|
112
139
|
end # Config
|
113
140
|
end # Mutant
|
data/lib/mutant/env.rb
CHANGED
@@ -24,10 +24,15 @@ module Mutant
|
|
24
24
|
# @param [Config] config
|
25
25
|
#
|
26
26
|
# @return [Env]
|
27
|
+
#
|
28
|
+
# rubocop:disable Metrics/MethodLength
|
27
29
|
def self.empty(world, config)
|
28
30
|
new(
|
29
31
|
config: config,
|
30
|
-
integration: Integration::Null.new(
|
32
|
+
integration: Integration::Null.new(
|
33
|
+
expression_parser: config.expression_parser,
|
34
|
+
timer: world.timer
|
35
|
+
),
|
31
36
|
matchable_scopes: EMPTY_ARRAY,
|
32
37
|
mutations: EMPTY_ARRAY,
|
33
38
|
parser: Parser.new,
|
@@ -36,6 +41,7 @@ module Mutant
|
|
36
41
|
world: world
|
37
42
|
)
|
38
43
|
end
|
44
|
+
# rubocop:enable Metrics/MethodLength
|
39
45
|
|
40
46
|
# Kill mutation
|
41
47
|
#
|
@@ -43,14 +49,14 @@ module Mutant
|
|
43
49
|
#
|
44
50
|
# @return [Result::Mutation]
|
45
51
|
def kill(mutation)
|
46
|
-
start =
|
52
|
+
start = timer.now
|
47
53
|
|
48
54
|
tests = selections.fetch(mutation.subject)
|
49
55
|
|
50
56
|
Result::Mutation.new(
|
51
57
|
isolation_result: run_mutation_tests(mutation, tests),
|
52
58
|
mutation: mutation,
|
53
|
-
runtime:
|
59
|
+
runtime: timer.now - start
|
54
60
|
)
|
55
61
|
end
|
56
62
|
|
@@ -127,7 +133,7 @@ module Mutant
|
|
127
133
|
private
|
128
134
|
|
129
135
|
def run_mutation_tests(mutation, tests)
|
130
|
-
config.isolation.call do
|
136
|
+
config.isolation.call(config.mutation_timeout) do
|
131
137
|
result = mutation.insert(world.kernel)
|
132
138
|
|
133
139
|
if result.equal?(Loader::Result::VoidValue.instance)
|
@@ -138,5 +144,9 @@ module Mutant
|
|
138
144
|
end
|
139
145
|
end
|
140
146
|
|
147
|
+
def timer
|
148
|
+
world.timer
|
149
|
+
end
|
150
|
+
|
141
151
|
end # Env
|
142
152
|
end # Mutant
|