mutant 0.8.22 → 0.8.23
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/Changelog.md +5 -0
- data/lib/mutant.rb +5 -4
- data/lib/mutant/env.rb +17 -17
- data/lib/mutant/isolation.rb +42 -1
- data/lib/mutant/isolation/fork.rb +118 -54
- data/lib/mutant/isolation/none.rb +4 -7
- data/lib/mutant/loader.rb +2 -2
- data/lib/mutant/mutation.rb +9 -8
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +112 -0
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +5 -7
- data/lib/mutant/result.rb +20 -12
- data/lib/mutant/runner/sink.rb +2 -2
- data/lib/mutant/version.rb +1 -1
- data/spec/support/shared_context.rb +34 -15
- data/spec/unit/mutant/env_spec.rb +64 -59
- data/spec/unit/mutant/isolation/fork_spec.rb +164 -70
- data/spec/unit/mutant/isolation/none_spec.rb +12 -7
- data/spec/unit/mutant/isolation/result_spec.rb +41 -0
- data/spec/unit/mutant/loader_spec.rb +1 -5
- data/spec/unit/mutant/mutation_spec.rb +4 -3
- data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +124 -0
- data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +21 -11
- data/spec/unit/mutant/result/env_spec.rb +51 -4
- data/spec/unit/mutant/result/mutation_spec.rb +40 -9
- metadata +8 -3
@@ -9,7 +9,7 @@ module Mutant
|
|
9
9
|
# :reek:TooManyConstants
|
10
10
|
class MutationResult < self
|
11
11
|
|
12
|
-
delegate :mutation, :
|
12
|
+
delegate :mutation, :isolation_result
|
13
13
|
|
14
14
|
MAP = {
|
15
15
|
Mutant::Mutation::Evil => :evil_details,
|
@@ -25,7 +25,6 @@ module Mutant
|
|
25
25
|
%s
|
26
26
|
Unparsed Source:
|
27
27
|
%s
|
28
|
-
Test Result:
|
29
28
|
MESSAGE
|
30
29
|
|
31
30
|
NO_DIFF_MESSAGE = <<~'MESSAGE'
|
@@ -47,7 +46,6 @@ module Mutant
|
|
47
46
|
---- Noop failure -----
|
48
47
|
No code was inserted. And the test did NOT PASS.
|
49
48
|
This is typically a problem of your specs not passing unmutated.
|
50
|
-
Test Result:
|
51
49
|
MESSAGE
|
52
50
|
|
53
51
|
FOOTER = '-----------------------'
|
@@ -68,6 +66,8 @@ module Mutant
|
|
68
66
|
# @return [undefined]
|
69
67
|
def print_details
|
70
68
|
__send__(MAP.fetch(mutation.class))
|
69
|
+
|
70
|
+
visit_isolation_result unless isolation_result.success?
|
71
71
|
end
|
72
72
|
|
73
73
|
# Evil mutation details
|
@@ -101,7 +101,6 @@ module Mutant
|
|
101
101
|
# @return [String]
|
102
102
|
def noop_details
|
103
103
|
info(NOOP_MESSAGE)
|
104
|
-
visit_test_result
|
105
104
|
end
|
106
105
|
|
107
106
|
# Neutral details
|
@@ -109,14 +108,13 @@ module Mutant
|
|
109
108
|
# @return [String]
|
110
109
|
def neutral_details
|
111
110
|
info(NEUTRAL_MESSAGE, original_node.inspect, mutation.source)
|
112
|
-
visit_test_result
|
113
111
|
end
|
114
112
|
|
115
113
|
# Visit failed test results
|
116
114
|
#
|
117
115
|
# @return [undefined]
|
118
|
-
def
|
119
|
-
visit(
|
116
|
+
def visit_isolation_result
|
117
|
+
visit(IsolationResult, isolation_result)
|
120
118
|
end
|
121
119
|
|
122
120
|
# Original node
|
data/lib/mutant/result.rb
CHANGED
@@ -108,6 +108,14 @@ module Mutant
|
|
108
108
|
env.subjects.length
|
109
109
|
end
|
110
110
|
|
111
|
+
# Test if processing needs to stop
|
112
|
+
#
|
113
|
+
# @return [Boolean]
|
114
|
+
#
|
115
|
+
def stop?
|
116
|
+
env.config.fail_fast && !subject_results.all?(&:success?)
|
117
|
+
end
|
118
|
+
|
111
119
|
end # Env
|
112
120
|
|
113
121
|
# Test result
|
@@ -189,30 +197,30 @@ module Mutant
|
|
189
197
|
# Mutation result
|
190
198
|
class Mutation
|
191
199
|
include Result, Anima.new(
|
200
|
+
:isolation_result,
|
192
201
|
:mutation,
|
193
|
-
:
|
202
|
+
:runtime
|
194
203
|
)
|
195
204
|
|
196
|
-
#
|
205
|
+
# Time the tests had been running
|
197
206
|
#
|
198
207
|
# @return [Float]
|
199
|
-
def
|
200
|
-
|
208
|
+
def killtime
|
209
|
+
if isolation_result.success?
|
210
|
+
isolation_result.value.runtime
|
211
|
+
else
|
212
|
+
0.0
|
213
|
+
end
|
201
214
|
end
|
202
215
|
|
203
|
-
# The time spent on killing
|
204
|
-
#
|
205
|
-
# @return [Float]
|
206
|
-
#
|
207
|
-
# @api private
|
208
|
-
alias_method :killtime, :runtime
|
209
|
-
|
210
216
|
# Test if mutation was handled successfully
|
211
217
|
#
|
212
218
|
# @return [Boolean]
|
213
219
|
def success?
|
214
|
-
|
220
|
+
isolation_result.success? &&
|
221
|
+
mutation.class.success?(isolation_result.value)
|
215
222
|
end
|
223
|
+
memoize :success?
|
216
224
|
|
217
225
|
end # Mutation
|
218
226
|
end # Result
|
data/lib/mutant/runner/sink.rb
CHANGED
@@ -29,7 +29,7 @@ module Mutant
|
|
29
29
|
#
|
30
30
|
# @return [Boolean]
|
31
31
|
def stop?
|
32
|
-
|
32
|
+
status.stop?
|
33
33
|
end
|
34
34
|
|
35
35
|
# Handle mutation finish
|
@@ -43,7 +43,7 @@ module Mutant
|
|
43
43
|
@subject_results[subject] = Result::Subject.new(
|
44
44
|
subject: subject,
|
45
45
|
mutation_results: previous_mutation_results(subject) + [mutation_result],
|
46
|
-
tests:
|
46
|
+
tests: env.selections.fetch(subject)
|
47
47
|
)
|
48
48
|
|
49
49
|
self
|
data/lib/mutant/version.rb
CHANGED
@@ -36,17 +36,26 @@ module SharedContext
|
|
36
36
|
# rubocop:disable MethodLength
|
37
37
|
# rubocop:disable AbcSize
|
38
38
|
def setup_shared_context
|
39
|
-
let(:
|
40
|
-
let(:
|
41
|
-
let(:
|
42
|
-
let(:
|
43
|
-
let(:
|
44
|
-
let(:
|
45
|
-
let(:
|
46
|
-
let(:
|
47
|
-
let(:
|
48
|
-
let(:
|
49
|
-
|
39
|
+
let(:job_a) { Mutant::Parallel::Job.new(index: 0, payload: mutation_a) }
|
40
|
+
let(:job_b) { Mutant::Parallel::Job.new(index: 1, payload: mutation_b) }
|
41
|
+
let(:mutation_a) { Mutant::Mutation::Evil.new(subject_a, mutation_a_node) }
|
42
|
+
let(:mutation_a_node) { s(:false) }
|
43
|
+
let(:mutation_b) { Mutant::Mutation::Evil.new(subject_a, mutation_b_node) }
|
44
|
+
let(:mutation_b_node) { s(:nil) }
|
45
|
+
let(:mutations) { [mutation_a, mutation_b] }
|
46
|
+
let(:output) { StringIO.new }
|
47
|
+
let(:subject_a_node) { s(:true) }
|
48
|
+
let(:test_a) { instance_double(Mutant::Test, identification: 'test-a') }
|
49
|
+
|
50
|
+
let(:env) do
|
51
|
+
instance_double(
|
52
|
+
Mutant::Env,
|
53
|
+
config: config,
|
54
|
+
mutations: mutations,
|
55
|
+
selections: { subject_a => [test_a] },
|
56
|
+
subjects: [subject_a]
|
57
|
+
)
|
58
|
+
end
|
50
59
|
|
51
60
|
let(:status) do
|
52
61
|
Mutant::Parallel::Status.new(
|
@@ -86,18 +95,24 @@ module SharedContext
|
|
86
95
|
|
87
96
|
let(:mutation_a_result) do
|
88
97
|
Mutant::Result::Mutation.new(
|
89
|
-
mutation:
|
90
|
-
|
98
|
+
mutation: mutation_a,
|
99
|
+
isolation_result: mutation_a_isolation_result,
|
100
|
+
runtime: 1.0
|
91
101
|
)
|
92
102
|
end
|
93
103
|
|
94
104
|
let(:mutation_b_result) do
|
95
105
|
Mutant::Result::Mutation.new(
|
96
|
-
|
97
|
-
|
106
|
+
isolation_result: mutation_b_isolation_result,
|
107
|
+
mutation: mutation_b,
|
108
|
+
runtime: 1.0
|
98
109
|
)
|
99
110
|
end
|
100
111
|
|
112
|
+
let(:mutation_a_isolation_result) do
|
113
|
+
Mutant::Isolation::Result::Success.new(mutation_a_test_result)
|
114
|
+
end
|
115
|
+
|
101
116
|
let(:mutation_a_test_result) do
|
102
117
|
Mutant::Result::Test.new(
|
103
118
|
tests: [test_a],
|
@@ -116,6 +131,10 @@ module SharedContext
|
|
116
131
|
)
|
117
132
|
end
|
118
133
|
|
134
|
+
let(:mutation_b_isolation_result) do
|
135
|
+
Mutant::Isolation::Result::Success.new(mutation_b_test_result)
|
136
|
+
end
|
137
|
+
|
119
138
|
let(:subject_a_result) do
|
120
139
|
Mutant::Result::Subject.new(
|
121
140
|
subject: subject_a,
|
@@ -1,73 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Mutant::Env do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
4
|
+
let(:object) do
|
5
|
+
described_class.new(
|
6
|
+
actor_env: Mutant::Actor::Env.new(Thread),
|
7
|
+
config: config,
|
8
|
+
integration: integration,
|
9
|
+
matchable_scopes: [],
|
10
|
+
mutations: [],
|
11
|
+
selector: selector,
|
12
|
+
subjects: [mutation_subject],
|
13
|
+
parser: Mutant::Parser.new
|
14
|
+
)
|
15
|
+
end
|
17
16
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
17
|
+
let(:integration) { instance_double(Mutant::Integration) }
|
18
|
+
let(:test_a) { instance_double(Mutant::Test) }
|
19
|
+
let(:test_b) { instance_double(Mutant::Test) }
|
20
|
+
let(:tests) { [test_a, test_b] }
|
21
|
+
let(:selector) { instance_double(Mutant::Selector) }
|
22
|
+
let(:integration_class) { Mutant::Integration::Null }
|
23
|
+
let(:isolation) { Mutant::Isolation::None.new }
|
24
|
+
let(:mutation_subject) { instance_double(Mutant::Subject) }
|
25
|
+
|
26
|
+
let(:mutation) do
|
27
|
+
instance_double(
|
28
|
+
Mutant::Mutation,
|
29
|
+
subject: mutation_subject
|
30
|
+
)
|
31
|
+
end
|
33
32
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
33
|
+
let(:config) do
|
34
|
+
Mutant::Config::DEFAULT.with(
|
35
|
+
isolation: isolation,
|
36
|
+
integration: integration_class,
|
37
|
+
kernel: class_double(Kernel)
|
38
|
+
)
|
39
|
+
end
|
41
40
|
|
41
|
+
before do
|
42
|
+
allow(selector).to receive(:call)
|
43
|
+
.with(mutation_subject)
|
44
|
+
.and_return(tests)
|
45
|
+
|
46
|
+
allow(Mutant::Timer).to receive(:now).and_return(2.0, 3.0)
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '#kill' do
|
42
50
|
subject { object.kill(mutation) }
|
43
51
|
|
44
52
|
shared_examples_for 'mutation kill' do
|
45
53
|
specify do
|
46
54
|
should eql(
|
47
55
|
Mutant::Result::Mutation.new(
|
48
|
-
|
49
|
-
|
56
|
+
isolation_result: isolation_result,
|
57
|
+
mutation: mutation,
|
58
|
+
runtime: 1.0
|
50
59
|
)
|
51
60
|
)
|
52
61
|
end
|
53
62
|
end
|
54
63
|
|
55
|
-
before do
|
56
|
-
expect(selector).to receive(:call)
|
57
|
-
.with(mutation_subject)
|
58
|
-
.and_return(tests)
|
59
|
-
|
60
|
-
allow(Mutant::Timer).to receive(:now).and_return(2.0, 3.0)
|
61
|
-
end
|
62
|
-
|
63
64
|
context 'when isolation does not raise error' do
|
64
65
|
let(:test_result) { instance_double(Mutant::Result::Test) }
|
65
66
|
|
66
67
|
before do
|
67
|
-
expect(isolation).to receive(:call)
|
68
|
-
.ordered
|
69
|
-
.and_yield
|
70
|
-
|
71
68
|
expect(mutation).to receive(:insert)
|
72
69
|
.ordered
|
73
70
|
.with(config.kernel)
|
@@ -78,25 +75,33 @@ RSpec.describe Mutant::Env do
|
|
78
75
|
.and_return(test_result)
|
79
76
|
end
|
80
77
|
|
78
|
+
let(:isolation_result) do
|
79
|
+
Mutant::Isolation::Result::Success.new(test_result)
|
80
|
+
end
|
81
|
+
|
81
82
|
include_examples 'mutation kill'
|
82
83
|
end
|
83
84
|
|
84
|
-
context 'when
|
85
|
+
context 'when code does raise error' do
|
86
|
+
let(:exception) { RuntimeError.new('foo') }
|
87
|
+
|
85
88
|
before do
|
86
|
-
expect(
|
87
|
-
.and_raise(Mutant::Isolation::Error, 'test-error')
|
89
|
+
expect(mutation).to receive(:insert).and_raise(exception)
|
88
90
|
end
|
89
91
|
|
90
|
-
let(:
|
91
|
-
Mutant::Result::
|
92
|
-
output: 'test-error',
|
93
|
-
passed: false,
|
94
|
-
runtime: 1.0,
|
95
|
-
tests: tests
|
96
|
-
)
|
92
|
+
let(:isolation_result) do
|
93
|
+
Mutant::Isolation::Result::Exception.new(exception)
|
97
94
|
end
|
98
95
|
|
99
96
|
include_examples 'mutation kill'
|
100
97
|
end
|
101
98
|
end
|
99
|
+
|
100
|
+
describe '#selections' do
|
101
|
+
subject { object.selections }
|
102
|
+
|
103
|
+
it 'returns expected selections' do
|
104
|
+
expect(subject).to eql(mutation_subject => tests)
|
105
|
+
end
|
106
|
+
end
|
102
107
|
end
|
@@ -23,6 +23,95 @@ RSpec.describe Mutant::Isolation::Fork do
|
|
23
23
|
let(:writer) { instance_double(IO, :writer) }
|
24
24
|
let(:nullio) { instance_double(IO, :nullio) }
|
25
25
|
|
26
|
+
let(:status_success) do
|
27
|
+
instance_double(Process::Status, success?: true)
|
28
|
+
end
|
29
|
+
|
30
|
+
let(:fork_success) do
|
31
|
+
{
|
32
|
+
receiver: process,
|
33
|
+
selector: :fork,
|
34
|
+
reaction: {
|
35
|
+
yields: [],
|
36
|
+
return: pid
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:child_wait) do
|
42
|
+
{
|
43
|
+
receiver: process,
|
44
|
+
selector: :wait2,
|
45
|
+
arguments: [pid],
|
46
|
+
reaction: {
|
47
|
+
return: [pid, status_success]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:writer_close) do
|
53
|
+
{
|
54
|
+
receiver: writer,
|
55
|
+
selector: :close
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
let(:load_success) do
|
60
|
+
{
|
61
|
+
receiver: marshal,
|
62
|
+
selector: :load,
|
63
|
+
arguments: [reader],
|
64
|
+
reaction: {
|
65
|
+
return: block_return
|
66
|
+
}
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
let(:killfork) do
|
71
|
+
[
|
72
|
+
# Inside the killfork
|
73
|
+
{
|
74
|
+
receiver: reader,
|
75
|
+
selector: :close
|
76
|
+
},
|
77
|
+
{
|
78
|
+
receiver: writer,
|
79
|
+
selector: :binmode
|
80
|
+
},
|
81
|
+
{
|
82
|
+
receiver: devnull,
|
83
|
+
selector: :call,
|
84
|
+
reaction: {
|
85
|
+
yields: [nullio]
|
86
|
+
}
|
87
|
+
},
|
88
|
+
{
|
89
|
+
receiver: stderr,
|
90
|
+
selector: :reopen,
|
91
|
+
arguments: [nullio]
|
92
|
+
},
|
93
|
+
{
|
94
|
+
receiver: stdout,
|
95
|
+
selector: :reopen,
|
96
|
+
arguments: [nullio]
|
97
|
+
},
|
98
|
+
{
|
99
|
+
receiver: marshal,
|
100
|
+
selector: :dump,
|
101
|
+
arguments: [block_return],
|
102
|
+
reaction: {
|
103
|
+
return: block_return_blob
|
104
|
+
}
|
105
|
+
},
|
106
|
+
{
|
107
|
+
receiver: writer,
|
108
|
+
selector: :syswrite,
|
109
|
+
arguments: [block_return_blob]
|
110
|
+
},
|
111
|
+
writer_close
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
26
115
|
describe '#call' do
|
27
116
|
let(:object) do
|
28
117
|
described_class.new(
|
@@ -51,6 +140,57 @@ RSpec.describe Mutant::Isolation::Fork do
|
|
51
140
|
end
|
52
141
|
|
53
142
|
context 'when no IO operation fails' do
|
143
|
+
let(:expectations) do
|
144
|
+
[
|
145
|
+
*prefork_expectations,
|
146
|
+
fork_success,
|
147
|
+
*killfork,
|
148
|
+
writer_close,
|
149
|
+
load_success,
|
150
|
+
child_wait
|
151
|
+
].map(&XSpec::MessageExpectation.method(:parse))
|
152
|
+
end
|
153
|
+
|
154
|
+
specify do
|
155
|
+
XSpec::ExpectationVerifier.verify(self, expectations) do
|
156
|
+
expect(subject).to eql(Mutant::Isolation::Result::Success.new(block_return))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'when expected exception was raised when reading from child' do
|
162
|
+
[ArgumentError, EOFError].each do |exception_class|
|
163
|
+
context "on #{exception_class}" do
|
164
|
+
let(:exception) { exception_class.new }
|
165
|
+
|
166
|
+
let(:expectations) do
|
167
|
+
[
|
168
|
+
*prefork_expectations,
|
169
|
+
fork_success,
|
170
|
+
*killfork,
|
171
|
+
{
|
172
|
+
receiver: writer,
|
173
|
+
selector: :close,
|
174
|
+
reaction: {
|
175
|
+
exception: exception
|
176
|
+
}
|
177
|
+
},
|
178
|
+
child_wait
|
179
|
+
].map(&XSpec::MessageExpectation.method(:parse))
|
180
|
+
end
|
181
|
+
|
182
|
+
specify do
|
183
|
+
XSpec::ExpectationVerifier.verify(self, expectations) do
|
184
|
+
expect(subject).to eql(Mutant::Isolation::Result::Exception.new(exception))
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'when fork fails' do
|
192
|
+
let(:result_class) { described_class::ForkError }
|
193
|
+
|
54
194
|
let(:expectations) do
|
55
195
|
[
|
56
196
|
*prefork_expectations,
|
@@ -58,90 +198,44 @@ RSpec.describe Mutant::Isolation::Fork do
|
|
58
198
|
receiver: process,
|
59
199
|
selector: :fork,
|
60
200
|
reaction: {
|
61
|
-
|
62
|
-
return: pid
|
63
|
-
}
|
64
|
-
},
|
65
|
-
# Inside the killfork
|
66
|
-
{
|
67
|
-
receiver: reader,
|
68
|
-
selector: :close
|
69
|
-
},
|
70
|
-
{
|
71
|
-
receiver: writer,
|
72
|
-
selector: :binmode
|
73
|
-
},
|
74
|
-
{
|
75
|
-
receiver: devnull,
|
76
|
-
selector: :call,
|
77
|
-
reaction: {
|
78
|
-
yields: [nullio]
|
201
|
+
return: nil
|
79
202
|
}
|
80
|
-
},
|
81
|
-
{
|
82
|
-
receiver: stderr,
|
83
|
-
selector: :reopen,
|
84
|
-
arguments: [nullio]
|
85
|
-
},
|
86
|
-
{
|
87
|
-
receiver: stdout,
|
88
|
-
selector: :reopen,
|
89
|
-
arguments: [nullio]
|
90
|
-
},
|
91
|
-
{
|
92
|
-
receiver: marshal,
|
93
|
-
selector: :dump,
|
94
|
-
arguments: [block_return],
|
95
|
-
reaction: {
|
96
|
-
return: block_return_blob
|
97
|
-
}
|
98
|
-
},
|
99
|
-
{
|
100
|
-
receiver: writer,
|
101
|
-
selector: :syswrite,
|
102
|
-
arguments: [block_return_blob]
|
103
|
-
},
|
104
|
-
{
|
105
|
-
receiver: writer,
|
106
|
-
selector: :close
|
107
|
-
},
|
108
|
-
# Outside the killfork
|
109
|
-
{
|
110
|
-
receiver: writer,
|
111
|
-
selector: :close
|
112
|
-
},
|
113
|
-
{
|
114
|
-
receiver: marshal,
|
115
|
-
selector: :load,
|
116
|
-
arguments: [reader],
|
117
|
-
reaction: {
|
118
|
-
return: block_return
|
119
|
-
}
|
120
|
-
},
|
121
|
-
{
|
122
|
-
receiver: process,
|
123
|
-
selector: :waitpid,
|
124
|
-
arguments: [pid]
|
125
203
|
}
|
126
204
|
].map(&XSpec::MessageExpectation.method(:parse))
|
127
205
|
end
|
128
206
|
|
129
207
|
specify do
|
130
208
|
XSpec::ExpectationVerifier.verify(self, expectations) do
|
131
|
-
expect(subject).to
|
209
|
+
expect(subject).to eql(result_class.new)
|
132
210
|
end
|
133
211
|
end
|
134
212
|
end
|
135
213
|
|
136
|
-
context 'when
|
214
|
+
context 'when child exits nonzero' do
|
215
|
+
let(:status_error) do
|
216
|
+
instance_double(Process::Status, success?: false)
|
217
|
+
end
|
218
|
+
|
219
|
+
let(:expected_result) do
|
220
|
+
Mutant::Isolation::Result::ErrorChain.new(
|
221
|
+
described_class::ChildError.new(status_error),
|
222
|
+
Mutant::Isolation::Result::Success.new(block_return)
|
223
|
+
)
|
224
|
+
end
|
225
|
+
|
137
226
|
let(:expectations) do
|
138
227
|
[
|
139
228
|
*prefork_expectations,
|
229
|
+
fork_success,
|
230
|
+
*killfork,
|
231
|
+
writer_close,
|
232
|
+
load_success,
|
140
233
|
{
|
141
|
-
receiver:
|
142
|
-
selector:
|
143
|
-
|
144
|
-
|
234
|
+
receiver: process,
|
235
|
+
selector: :wait2,
|
236
|
+
arguments: [pid],
|
237
|
+
reaction: {
|
238
|
+
return: [pid, status_error]
|
145
239
|
}
|
146
240
|
}
|
147
241
|
].map(&XSpec::MessageExpectation.method(:parse))
|
@@ -149,7 +243,7 @@ RSpec.describe Mutant::Isolation::Fork do
|
|
149
243
|
|
150
244
|
specify do
|
151
245
|
XSpec::ExpectationVerifier.verify(self, expectations) do
|
152
|
-
expect
|
246
|
+
expect(subject).to eql(expected_result)
|
153
247
|
end
|
154
248
|
end
|
155
249
|
end
|