mutant 0.8.24 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +3 -3
- data/Changelog.md +14 -654
- data/Gemfile +13 -0
- data/Gemfile.lock +59 -64
- data/LICENSE +271 -20
- data/README.md +73 -140
- data/Rakefile +0 -21
- data/bin/mutant +7 -2
- data/config/reek.yml +2 -1
- data/config/rubocop.yml +5 -9
- data/docs/incremental.md +76 -0
- data/docs/known-problems.md +0 -14
- data/docs/mutant-minitest.md +1 -1
- data/docs/mutant-rspec.md +2 -24
- data/lib/mutant.rb +45 -53
- data/lib/mutant/ast/nodes.rb +0 -2
- data/lib/mutant/ast/types.rb +1 -117
- data/lib/mutant/base.rb +192 -0
- data/lib/mutant/bootstrap.rb +145 -0
- data/lib/mutant/cli.rb +68 -54
- data/lib/mutant/config.rb +119 -6
- data/lib/mutant/env.rb +94 -8
- data/lib/mutant/expression.rb +6 -1
- data/lib/mutant/expression/parser.rb +9 -31
- data/lib/mutant/integration.rb +64 -36
- data/lib/mutant/isolation.rb +16 -1
- data/lib/mutant/isolation/fork.rb +105 -40
- data/lib/mutant/license.rb +34 -0
- data/lib/mutant/license/subscription.rb +47 -0
- data/lib/mutant/license/subscription/commercial.rb +57 -0
- data/lib/mutant/license/subscription/opensource.rb +77 -0
- data/lib/mutant/loader.rb +27 -4
- data/lib/mutant/matcher.rb +48 -1
- data/lib/mutant/matcher/chain.rb +1 -1
- data/lib/mutant/matcher/config.rb +0 -2
- data/lib/mutant/matcher/filter.rb +1 -1
- data/lib/mutant/matcher/method.rb +11 -7
- data/lib/mutant/matcher/methods.rb +1 -1
- data/lib/mutant/matcher/namespace.rb +1 -1
- data/lib/mutant/matcher/null.rb +1 -1
- data/lib/mutant/matcher/scope.rb +1 -1
- data/lib/mutant/meta/example/dsl.rb +0 -8
- data/lib/mutant/mutation.rb +1 -2
- data/lib/mutant/mutator/node.rb +2 -9
- data/lib/mutant/mutator/node/arguments.rb +1 -1
- data/lib/mutant/mutator/node/class.rb +0 -8
- data/lib/mutant/mutator/node/define.rb +0 -12
- data/lib/mutant/mutator/node/generic.rb +30 -44
- data/lib/mutant/mutator/node/index.rb +4 -4
- data/lib/mutant/mutator/node/literal/regex.rb +0 -39
- data/lib/mutant/mutator/node/send.rb +13 -12
- data/lib/mutant/parallel.rb +61 -40
- data/lib/mutant/parallel/driver.rb +59 -0
- data/lib/mutant/parallel/source.rb +6 -2
- data/lib/mutant/parallel/worker.rb +63 -45
- data/lib/mutant/range.rb +15 -0
- data/lib/mutant/reporter/cli.rb +5 -11
- data/lib/mutant/reporter/cli/format.rb +3 -46
- data/lib/mutant/reporter/cli/printer/config.rb +5 -6
- data/lib/mutant/reporter/cli/printer/env.rb +40 -0
- data/lib/mutant/reporter/cli/printer/env_progress.rb +13 -17
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +17 -3
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -3
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +19 -10
- data/lib/mutant/repository.rb +0 -65
- data/lib/mutant/repository/diff.rb +104 -0
- data/lib/mutant/repository/diff/ranges.rb +52 -0
- data/lib/mutant/result.rb +16 -7
- data/lib/mutant/runner.rb +38 -47
- data/lib/mutant/runner/sink.rb +1 -1
- data/lib/mutant/selector/null.rb +19 -0
- data/lib/mutant/subject.rb +3 -1
- data/lib/mutant/subject/method/instance.rb +3 -1
- data/lib/mutant/transform.rb +511 -0
- data/lib/mutant/variable.rb +282 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warnings.rb +113 -0
- data/meta/case.rb +1 -0
- data/meta/class.rb +0 -9
- data/meta/def.rb +1 -26
- data/meta/regexp.rb +10 -20
- data/meta/send.rb +14 -46
- data/mutant-minitest.gemspec +1 -1
- data/mutant-rspec.gemspec +2 -2
- data/mutant.gemspec +15 -16
- data/mutant.yml +6 -0
- data/spec/integration/mutant/isolation/fork_spec.rb +22 -5
- data/spec/integration/mutant/minitest_spec.rb +3 -2
- data/spec/integration/mutant/rspec_spec.rb +4 -3
- data/spec/integrations.yml +16 -13
- data/spec/shared/base_behavior.rb +45 -0
- data/spec/shared/framework_integration_behavior.rb +43 -14
- data/spec/spec_helper.rb +21 -17
- data/spec/support/corpus.rb +56 -95
- data/spec/support/shared_context.rb +37 -14
- data/spec/support/xspec.rb +7 -3
- data/spec/unit/mutant/bootstrap_spec.rb +216 -0
- data/spec/unit/mutant/cli_spec.rb +173 -117
- data/spec/unit/mutant/config_spec.rb +126 -0
- data/spec/unit/mutant/either_spec.rb +247 -0
- data/spec/unit/mutant/env_spec.rb +162 -40
- data/spec/unit/mutant/expression/method_spec.rb +16 -0
- data/spec/unit/mutant/expression/parser_spec.rb +29 -33
- data/spec/unit/mutant/expression_spec.rb +5 -7
- data/spec/unit/mutant/integration_spec.rb +100 -9
- data/spec/unit/mutant/isolation/fork_spec.rb +125 -67
- data/spec/unit/mutant/isolation/result_spec.rb +33 -1
- data/spec/unit/mutant/license_spec.rb +257 -0
- data/spec/unit/mutant/loader_spec.rb +50 -11
- data/spec/unit/mutant/matcher/compiler_spec.rb +0 -78
- data/spec/unit/mutant/matcher/method/instance_spec.rb +55 -11
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +12 -2
- data/spec/unit/mutant/matcher_spec.rb +102 -0
- data/spec/unit/mutant/maybe_spec.rb +60 -0
- data/spec/unit/mutant/meta/example/dsl_spec.rb +1 -17
- data/spec/unit/mutant/mutation_spec.rb +13 -6
- data/spec/unit/mutant/parallel/driver_spec.rb +112 -14
- data/spec/unit/mutant/parallel/source/array_spec.rb +25 -17
- data/spec/unit/mutant/parallel/worker_spec.rb +182 -44
- data/spec/unit/mutant/parallel_spec.rb +105 -8
- data/spec/unit/mutant/range_spec.rb +141 -0
- data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +7 -21
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +15 -6
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +10 -2
- data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +12 -4
- data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +31 -2
- data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +4 -4
- data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +5 -0
- data/spec/unit/mutant/reporter/cli_spec.rb +46 -123
- data/spec/unit/mutant/repository/diff/ranges_spec.rb +180 -0
- data/spec/unit/mutant/repository/diff_spec.rb +84 -71
- data/spec/unit/mutant/require_highjack_spec.rb +1 -1
- data/spec/unit/mutant/result/env_spec.rb +39 -9
- data/spec/unit/mutant/result/test_spec.rb +14 -0
- data/spec/unit/mutant/runner_spec.rb +88 -41
- data/spec/unit/mutant/selector/expression_spec.rb +11 -10
- data/spec/unit/mutant/selector/null_spec.rb +17 -0
- data/spec/unit/mutant/subject/method/instance_spec.rb +44 -5
- data/spec/unit/mutant/subject/method/singleton_spec.rb +9 -2
- data/spec/unit/mutant/subject_spec.rb +9 -1
- data/spec/unit/mutant/transform/array_spec.rb +92 -0
- data/spec/unit/mutant/transform/bool_spec.rb +63 -0
- data/spec/unit/mutant/transform/error_spec.rb +132 -0
- data/spec/unit/mutant/transform/exception_spec.rb +44 -0
- data/spec/unit/mutant/transform/hash_spec.rb +236 -0
- data/spec/unit/mutant/transform/index_spec.rb +92 -0
- data/spec/unit/mutant/transform/named_spec.rb +49 -0
- data/spec/unit/mutant/transform/primitive_spec.rb +56 -0
- data/spec/unit/mutant/transform/sequence_spec.rb +98 -0
- data/spec/unit/mutant/variable_spec.rb +618 -0
- data/spec/unit/mutant/warnings_spec.rb +89 -0
- data/spec/unit/mutant/world_spec.rb +63 -0
- data/test_app/Gemfile.minitest +0 -2
- metadata +79 -113
- data/.gitattributes +0 -1
- data/.ruby-gemset +0 -1
- data/config/triage.yml +0 -2
- data/lib/mutant/actor.rb +0 -57
- data/lib/mutant/actor/env.rb +0 -31
- data/lib/mutant/actor/mailbox.rb +0 -34
- data/lib/mutant/actor/receiver.rb +0 -42
- data/lib/mutant/actor/sender.rb +0 -26
- data/lib/mutant/ast/meta/restarg.rb +0 -19
- data/lib/mutant/ast/regexp.rb +0 -42
- data/lib/mutant/ast/regexp/transformer.rb +0 -187
- data/lib/mutant/ast/regexp/transformer/direct.rb +0 -123
- data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -59
- data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -83
- data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -114
- data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -58
- data/lib/mutant/ast/regexp/transformer/root.rb +0 -31
- data/lib/mutant/ast/regexp/transformer/text.rb +0 -60
- data/lib/mutant/env/bootstrap.rb +0 -160
- data/lib/mutant/matcher/compiler.rb +0 -60
- data/lib/mutant/mutator/node/regexp.rb +0 -35
- data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -23
- data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -28
- data/lib/mutant/mutator/node/regexp/character_type.rb +0 -32
- data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -23
- data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -23
- data/lib/mutant/mutator/node/regexp/greedy_zero_or_more.rb +0 -27
- data/lib/mutant/parallel/master.rb +0 -181
- data/lib/mutant/reporter/cli/printer/status.rb +0 -53
- data/lib/mutant/reporter/cli/tput.rb +0 -46
- data/lib/mutant/warning_filter.rb +0 -61
- data/meta/regexp/character_types.rb +0 -23
- data/meta/regexp/regexp_alternation_meta.rb +0 -13
- data/meta/regexp/regexp_bol_anchor.rb +0 -10
- data/meta/regexp/regexp_bos_anchor.rb +0 -18
- data/meta/regexp/regexp_capture_group.rb +0 -19
- data/meta/regexp/regexp_eol_anchor.rb +0 -10
- data/meta/regexp/regexp_eos_anchor.rb +0 -8
- data/meta/regexp/regexp_eos_ob_eol_anchor.rb +0 -10
- data/meta/regexp/regexp_greedy_zero_or_more.rb +0 -12
- data/meta/regexp/regexp_root_expression.rb +0 -10
- data/meta/restarg.rb +0 -10
- data/spec/support/fake_actor.rb +0 -111
- data/spec/support/warning.rb +0 -66
- data/spec/unit/mutant/actor/binding_spec.rb +0 -34
- data/spec/unit/mutant/actor/env_spec.rb +0 -31
- data/spec/unit/mutant/actor/mailbox_spec.rb +0 -28
- data/spec/unit/mutant/actor/message_spec.rb +0 -25
- data/spec/unit/mutant/actor/receiver_spec.rb +0 -58
- data/spec/unit/mutant/actor/sender_spec.rb +0 -24
- data/spec/unit/mutant/ast/regexp/parse_spec.rb +0 -19
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +0 -21
- data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +0 -35
- data/spec/unit/mutant/ast/regexp/transformer_spec.rb +0 -21
- data/spec/unit/mutant/ast/regexp_spec.rb +0 -704
- data/spec/unit/mutant/env/bootstrap_spec.rb +0 -188
- data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +0 -26
- data/spec/unit/mutant/parallel/master_spec.rb +0 -338
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -121
- data/spec/unit/mutant/reporter/cli/tput_spec.rb +0 -50
- data/spec/unit/mutant/warning_filter_spec.rb +0 -106
- data/spec/unit/mutant_spec.rb +0 -17
- data/test_app/Gemfile.rspec3.7 +0 -7
@@ -1,49 +1,57 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Mutant::Parallel::Source::Array do
|
4
|
-
|
4
|
+
subject { described_class.new(payloads) }
|
5
5
|
|
6
|
-
let(:
|
7
|
-
let(:job_b) { instance_double(Mutant::Parallel::Job) }
|
8
|
-
let(:job_c) { instance_double(Mutant::Parallel::Job) }
|
9
|
-
|
10
|
-
let(:jobs) { [job_a, job_b, job_c] }
|
6
|
+
let(:payloads) { %i[a b c] }
|
11
7
|
|
12
8
|
describe '#next' do
|
13
|
-
|
9
|
+
def job(**attributes)
|
10
|
+
Mutant::Parallel::Source::Job.new(attributes)
|
11
|
+
end
|
12
|
+
|
13
|
+
def apply
|
14
|
+
subject.next
|
15
|
+
end
|
14
16
|
|
15
17
|
context 'when there is a next job' do
|
16
18
|
it 'returns that job' do
|
17
|
-
|
19
|
+
expect(apply).to eql(job(index: 0, payload: :a))
|
18
20
|
end
|
19
21
|
|
20
22
|
it 'does not return the same job twice' do
|
21
|
-
expect(
|
22
|
-
expect(
|
23
|
-
expect(
|
23
|
+
expect(apply).to eql(job(index: 0, payload: :a))
|
24
|
+
expect(apply).to eql(job(index: 1, payload: :b))
|
25
|
+
expect(apply).to eql(job(index: 2, payload: :c))
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
27
29
|
context 'when there is no next job' do
|
28
|
-
let(:
|
30
|
+
let(:payloads) { [] }
|
29
31
|
|
30
32
|
it 'raises error' do
|
31
|
-
expect {
|
33
|
+
expect { apply }.to raise_error(Mutant::Parallel::Source::NoJobError)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
describe '#next?' do
|
37
|
-
|
39
|
+
def apply
|
40
|
+
subject.next?
|
41
|
+
end
|
38
42
|
|
39
43
|
context 'when there is a next job' do
|
40
|
-
it
|
44
|
+
it 'returns true' do
|
45
|
+
expect(apply).to be(true)
|
46
|
+
end
|
41
47
|
end
|
42
48
|
|
43
49
|
context 'when there is no next job' do
|
44
|
-
let(:
|
50
|
+
let(:payloads) { [] }
|
45
51
|
|
46
|
-
it
|
52
|
+
it 'returns false' do
|
53
|
+
expect(apply).to be(false)
|
54
|
+
end
|
47
55
|
end
|
48
56
|
end
|
49
57
|
end
|
@@ -1,68 +1,206 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
RSpec.describe Mutant::Parallel::Worker do
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
describe '#call' do
|
5
|
+
let(:active_jobs) { instance_double(Set) }
|
6
|
+
let(:payload_a) { instance_double(Object) }
|
7
|
+
let(:payload_b) { instance_double(Object) }
|
8
|
+
let(:processor) { instance_double(Proc) }
|
9
|
+
let(:result_a) { instance_double(Object) }
|
10
|
+
let(:result_b) { instance_double(Object) }
|
11
|
+
let(:running) { 1 }
|
12
|
+
let(:sink) { instance_double(Mutant::Parallel::Sink) }
|
13
|
+
let(:source) { instance_double(Mutant::Parallel::Source) }
|
14
|
+
let(:thread_a) { instance_double(Thread, alive?: true) }
|
15
|
+
let(:thread_b) { instance_double(Thread, alive?: true) }
|
16
|
+
let(:threads) { [thread_a, thread_b] }
|
17
|
+
let(:timeout) { instance_double(Float) }
|
7
18
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
let(:attributes) do
|
16
|
-
{
|
17
|
-
processor: processor,
|
18
|
-
parent: parent,
|
19
|
-
mailbox: mailbox
|
20
|
-
}
|
21
|
-
end
|
19
|
+
let(:job_a) do
|
20
|
+
instance_double(
|
21
|
+
Mutant::Parallel::Source::Job,
|
22
|
+
payload: payload_a
|
23
|
+
)
|
24
|
+
end
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
let(:job_b) do
|
27
|
+
instance_double(
|
28
|
+
Mutant::Parallel::Source::Job,
|
29
|
+
payload: payload_b
|
30
|
+
)
|
31
|
+
end
|
26
32
|
|
27
|
-
|
28
|
-
|
33
|
+
let(:var_active_jobs) do
|
34
|
+
instance_double(Mutant::Variable::IVar, 'active jobs')
|
35
|
+
end
|
29
36
|
|
30
|
-
let(:
|
37
|
+
let(:var_final) do
|
38
|
+
instance_double(Mutant::Variable::IVar, 'final')
|
39
|
+
end
|
31
40
|
|
32
|
-
|
41
|
+
let(:var_running) do
|
42
|
+
instance_double(Mutant::Variable::MVar, 'running')
|
43
|
+
end
|
33
44
|
|
34
|
-
|
35
|
-
|
45
|
+
let(:var_sink) do
|
46
|
+
instance_double(Mutant::Variable::IVar, 'sink')
|
47
|
+
end
|
36
48
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
49
|
+
let(:var_source) do
|
50
|
+
instance_double(Mutant::Variable::IVar, 'source')
|
51
|
+
end
|
52
|
+
|
53
|
+
subject do
|
54
|
+
described_class.new(
|
55
|
+
processor: processor,
|
56
|
+
var_active_jobs: var_active_jobs,
|
57
|
+
var_final: var_final,
|
58
|
+
var_running: var_running,
|
59
|
+
var_sink: var_sink,
|
60
|
+
var_source: var_source
|
61
|
+
)
|
62
|
+
end
|
63
|
+
|
64
|
+
def apply
|
65
|
+
subject.call
|
66
|
+
end
|
42
67
|
|
43
|
-
|
44
|
-
|
45
|
-
|
68
|
+
def sink_result(result)
|
69
|
+
{
|
70
|
+
receiver: sink,
|
71
|
+
selector: :result,
|
72
|
+
arguments: [result]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def sink_stop?(value)
|
77
|
+
{
|
78
|
+
receiver: sink,
|
79
|
+
selector: :stop?,
|
80
|
+
reaction: { return: value }
|
81
|
+
}
|
82
|
+
end
|
83
|
+
|
84
|
+
def source_next?(value)
|
85
|
+
{
|
86
|
+
receiver: source,
|
87
|
+
selector: :next?,
|
88
|
+
reaction: { return: value }
|
89
|
+
}
|
90
|
+
end
|
46
91
|
|
47
|
-
|
48
|
-
|
92
|
+
def source_next(value)
|
93
|
+
{
|
94
|
+
receiver: source,
|
95
|
+
selector: :next,
|
96
|
+
reaction: { return: value }
|
97
|
+
}
|
98
|
+
end
|
99
|
+
|
100
|
+
def with(var, value)
|
101
|
+
{
|
102
|
+
receiver: var,
|
103
|
+
selector: :with,
|
104
|
+
reaction: { yields: [value] }
|
105
|
+
}
|
106
|
+
end
|
107
|
+
|
108
|
+
def process(payload, result)
|
109
|
+
{
|
110
|
+
receiver: processor,
|
111
|
+
selector: :call,
|
112
|
+
arguments: [payload],
|
113
|
+
reaction: { return: result }
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_job(job)
|
118
|
+
{
|
119
|
+
receiver: active_jobs,
|
120
|
+
selector: :<<,
|
121
|
+
arguments: [job]
|
122
|
+
}
|
123
|
+
end
|
124
|
+
|
125
|
+
def remove_job(job)
|
126
|
+
{
|
127
|
+
receiver: active_jobs,
|
128
|
+
selector: :delete,
|
129
|
+
arguments: [job]
|
130
|
+
}
|
131
|
+
end
|
132
|
+
|
133
|
+
shared_examples 'worker execution' do
|
134
|
+
it 'terminates after processing all jobs' do
|
135
|
+
verify_events { expect(apply).to be(subject) }
|
49
136
|
end
|
137
|
+
end
|
50
138
|
|
51
|
-
|
139
|
+
def modify_running
|
140
|
+
{
|
141
|
+
receiver: var_running,
|
142
|
+
selector: :modify,
|
143
|
+
reaction: { yields: [running] }
|
144
|
+
}
|
145
|
+
end
|
52
146
|
|
53
|
-
|
54
|
-
|
147
|
+
def finalize
|
148
|
+
[
|
149
|
+
modify_running,
|
150
|
+
{
|
151
|
+
receiver: var_final,
|
152
|
+
selector: :put,
|
153
|
+
arguments: [nil]
|
154
|
+
}
|
155
|
+
]
|
156
|
+
end
|
157
|
+
|
158
|
+
context 'when processing jobs till sink stops accepting' do
|
159
|
+
let(:raw_expectations) do
|
160
|
+
[
|
161
|
+
with(var_source, source),
|
162
|
+
source_next?(true),
|
163
|
+
source_next(job_a),
|
164
|
+
with(var_active_jobs, active_jobs),
|
165
|
+
add_job(job_a),
|
166
|
+
process(payload_a, result_a),
|
167
|
+
with(var_active_jobs, active_jobs),
|
168
|
+
remove_job(job_a),
|
169
|
+
with(var_sink, sink),
|
170
|
+
sink_result(result_a),
|
171
|
+
sink_stop?(true),
|
172
|
+
*finalize
|
173
|
+
]
|
55
174
|
end
|
175
|
+
|
176
|
+
include_examples 'worker execution'
|
56
177
|
end
|
57
178
|
|
58
|
-
context 'when
|
59
|
-
|
60
|
-
|
179
|
+
context 'when processing jobs till source is empty' do
|
180
|
+
let(:raw_expectations) do
|
181
|
+
[
|
182
|
+
with(var_source, source),
|
183
|
+
source_next?(false),
|
184
|
+
*finalize
|
185
|
+
]
|
61
186
|
end
|
62
187
|
|
63
|
-
|
64
|
-
|
188
|
+
include_examples 'worker execution'
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'when worker exits as others are still going' do
|
192
|
+
let(:running) { 2 }
|
193
|
+
|
194
|
+
let(:raw_expectations) do
|
195
|
+
[
|
196
|
+
with(var_source, source),
|
197
|
+
source_next?(false),
|
198
|
+
modify_running
|
199
|
+
# no finalize
|
200
|
+
]
|
65
201
|
end
|
202
|
+
|
203
|
+
include_examples 'worker execution'
|
66
204
|
end
|
67
205
|
end
|
68
206
|
end
|
@@ -2,17 +2,114 @@
|
|
2
2
|
|
3
3
|
RSpec.describe Mutant::Parallel do
|
4
4
|
describe '.async' do
|
5
|
-
|
5
|
+
def apply
|
6
|
+
described_class.async(config)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:condition_variable) { class_double(ConditionVariable) }
|
10
|
+
let(:jobs) { 2 }
|
11
|
+
let(:mutex) { class_double(Mutex) }
|
12
|
+
let(:processor) { instance_double(Proc) }
|
13
|
+
let(:sink) { instance_double(described_class::Sink) }
|
14
|
+
let(:source) { instance_double(described_class::Source) }
|
15
|
+
let(:thread) { class_double(Thread) }
|
16
|
+
let(:thread_a) { instance_double(Thread) }
|
17
|
+
let(:thread_b) { instance_double(Thread) }
|
18
|
+
let(:worker) { -> {} }
|
19
|
+
|
20
|
+
let(:config) do
|
21
|
+
Mutant::Parallel::Config.new(
|
22
|
+
condition_variable: condition_variable,
|
23
|
+
jobs: jobs,
|
24
|
+
mutex: mutex,
|
25
|
+
processor: processor,
|
26
|
+
sink: sink,
|
27
|
+
source: source,
|
28
|
+
thread: thread
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
let(:var_active_jobs) do
|
33
|
+
instance_double(Mutant::Variable::IVar, 'active jobs')
|
34
|
+
end
|
35
|
+
|
36
|
+
let(:var_final) do
|
37
|
+
instance_double(Mutant::Variable::IVar, 'final')
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:var_running) do
|
41
|
+
instance_double(Mutant::Variable::MVar, 'running')
|
42
|
+
end
|
6
43
|
|
7
|
-
let(:
|
8
|
-
|
9
|
-
|
10
|
-
let(:master) { instance_double(Mutant::Parallel::Master) }
|
44
|
+
let(:var_sink) do
|
45
|
+
instance_double(Mutant::Variable::IVar, 'sink')
|
46
|
+
end
|
11
47
|
|
12
|
-
|
13
|
-
|
48
|
+
let(:var_source) do
|
49
|
+
instance_double(Mutant::Variable::IVar, 'source')
|
14
50
|
end
|
15
51
|
|
16
|
-
|
52
|
+
def ivar(value, **attributes)
|
53
|
+
{
|
54
|
+
receiver: Mutant::Variable::IVar,
|
55
|
+
selector: :new,
|
56
|
+
arguments: [
|
57
|
+
condition_variable: condition_variable,
|
58
|
+
mutex: mutex,
|
59
|
+
**attributes
|
60
|
+
],
|
61
|
+
reaction: { return: value }
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def mvar(*arguments)
|
66
|
+
ivar(*arguments).merge(receiver: Mutant::Variable::MVar)
|
67
|
+
end
|
68
|
+
|
69
|
+
let(:raw_expectations) do
|
70
|
+
[
|
71
|
+
ivar(var_active_jobs, value: Set.new),
|
72
|
+
ivar(var_final),
|
73
|
+
ivar(var_sink, value: sink),
|
74
|
+
mvar(var_running, value: 2),
|
75
|
+
ivar(var_source, value: source),
|
76
|
+
{
|
77
|
+
receiver: Mutant::Parallel::Worker,
|
78
|
+
selector: :new,
|
79
|
+
arguments: [
|
80
|
+
processor: processor,
|
81
|
+
var_active_jobs: var_active_jobs,
|
82
|
+
var_final: var_final,
|
83
|
+
var_running: var_running,
|
84
|
+
var_sink: var_sink,
|
85
|
+
var_source: var_source
|
86
|
+
],
|
87
|
+
reaction: { return: worker }
|
88
|
+
},
|
89
|
+
{
|
90
|
+
receiver: thread,
|
91
|
+
selector: :new,
|
92
|
+
reaction: { yields: [], return: thread_a }
|
93
|
+
},
|
94
|
+
{
|
95
|
+
receiver: thread,
|
96
|
+
selector: :new,
|
97
|
+
reaction: { yields: [], return: thread_b }
|
98
|
+
}
|
99
|
+
]
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns driver' do
|
103
|
+
verify_events do
|
104
|
+
expect(apply).to eql(
|
105
|
+
described_class::Driver.new(
|
106
|
+
threads: [thread_a, thread_b],
|
107
|
+
var_active_jobs: var_active_jobs,
|
108
|
+
var_final: var_final,
|
109
|
+
var_sink: var_sink
|
110
|
+
)
|
111
|
+
)
|
112
|
+
end
|
113
|
+
end
|
17
114
|
end
|
18
115
|
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe Mutant::Range do
|
4
|
+
describe '.overlap?' do
|
5
|
+
def apply
|
6
|
+
described_class.overlap?(left, right)
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'no overlap left before right' do
|
10
|
+
# |---|
|
11
|
+
# |---|
|
12
|
+
let(:left) { 1..2 }
|
13
|
+
let(:right) { 3..4 }
|
14
|
+
|
15
|
+
it 'returns false' do
|
16
|
+
expect(apply).to be(false)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
context 'no overlap right before left' do
|
21
|
+
# |---|
|
22
|
+
# |---|
|
23
|
+
let(:left) { 3..4 }
|
24
|
+
let(:right) { 1..2 }
|
25
|
+
|
26
|
+
it 'returns false' do
|
27
|
+
expect(apply).to be(false)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context 'left includes right' do
|
32
|
+
# |----------------|
|
33
|
+
# |---|
|
34
|
+
let(:left) { 1..4 }
|
35
|
+
let(:right) { 2..3 }
|
36
|
+
|
37
|
+
it 'returns true' do
|
38
|
+
expect(apply).to be(true)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context 'right includes left' do
|
43
|
+
# |---|
|
44
|
+
# |----------------|
|
45
|
+
let(:left) { 2..3 }
|
46
|
+
let(:right) { 1..4 }
|
47
|
+
|
48
|
+
it 'returns true' do
|
49
|
+
expect(apply).to be(true)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'right starts with left end' do
|
54
|
+
# |----|
|
55
|
+
# |----|
|
56
|
+
let(:left) { 1..2 }
|
57
|
+
let(:right) { 2..3 }
|
58
|
+
|
59
|
+
it 'returns true' do
|
60
|
+
expect(apply).to be(true)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context 'left starts with right end' do
|
65
|
+
# |----|
|
66
|
+
# |----|
|
67
|
+
let(:left) { 2..3 }
|
68
|
+
let(:right) { 1..2 }
|
69
|
+
|
70
|
+
it 'returns true' do
|
71
|
+
expect(apply).to be(true)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'left starts with right start' do
|
76
|
+
# |----|
|
77
|
+
# |---------|
|
78
|
+
let(:left) { 1..2 }
|
79
|
+
let(:right) { 1..3 }
|
80
|
+
|
81
|
+
it 'returns true' do
|
82
|
+
expect(apply).to be(true)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'left starts with right start' do
|
87
|
+
# |---------|
|
88
|
+
# |----|
|
89
|
+
let(:left) { 1..3 }
|
90
|
+
let(:right) { 1..2 }
|
91
|
+
|
92
|
+
it 'returns true' do
|
93
|
+
expect(apply).to be(true)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'left ends with right end' do
|
98
|
+
# |----|
|
99
|
+
# |---------|
|
100
|
+
let(:left) { 2..3 }
|
101
|
+
let(:right) { 1..3 }
|
102
|
+
|
103
|
+
it 'returns true' do
|
104
|
+
expect(apply).to be(true)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context 'right ends with left end' do
|
109
|
+
# |---------|
|
110
|
+
# |----|
|
111
|
+
let(:left) { 1..3 }
|
112
|
+
let(:right) { 2..3 }
|
113
|
+
|
114
|
+
it 'returns true' do
|
115
|
+
expect(apply).to be(true)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context 'left end intersects with right' do
|
120
|
+
# |---------|
|
121
|
+
# |----------|
|
122
|
+
let(:left) { 1..3 }
|
123
|
+
let(:right) { 2..4 }
|
124
|
+
|
125
|
+
it 'returns true' do
|
126
|
+
expect(apply).to be(true)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'right end intersects with left' do
|
131
|
+
# |----------|
|
132
|
+
# |---------|
|
133
|
+
let(:left) { 2..4 }
|
134
|
+
let(:right) { 1..2 }
|
135
|
+
|
136
|
+
it 'returns true' do
|
137
|
+
expect(apply).to be(true)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|