mutant 0.9.5 → 0.9.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/Changelog.md +5 -0
- data/Gemfile.lock +4 -1
- data/lib/mutant.rb +1 -1
- data/lib/mutant/license.rb +1 -1
- data/lib/mutant/parallel.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- data/mutant.gemspec +1 -0
- data/spec/integrations.yml +3 -1
- data/spec/unit/mutant/license_spec.rb +2 -2
- data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
- data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
- data/spec/unit/mutant/parallel_spec.rb +7 -7
- metadata +17 -6
- data/lib/mutant/variable.rb +0 -282
- data/spec/unit/mutant/variable_spec.rb +0 -618
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ef6c23cfd4cebac6873c8d422c919b3821a4eb09cb77b8b9786185fb711c7f70
|
4
|
+
data.tar.gz: 3035168adda27d5ba4476606ddbf84ddeba62d00bf12a9a26d9b55fcc48a8a74
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b137d304dfd008cb9e12373c9665fcd494ddaad91e630ee1cd0bf96ace97abb0181513d152d61dba38dab9ed71f9a473b441983e9e04361e1c4bced66449410
|
7
|
+
data.tar.gz: f1566c734cb33af620ae3a1d440cd26f9b2c8f8ecf9665bfade140438b5d5e2e8c21732db42cb6bb2130aae87481a11324ca47dac4fb51f17065ee7e2262f8f6
|
data/Changelog.md
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
mutant (0.9.
|
4
|
+
mutant (0.9.6)
|
5
5
|
abstract_type (~> 0.0.7)
|
6
6
|
adamantium (~> 0.2.0)
|
7
7
|
anima (~> 0.3.1)
|
@@ -15,6 +15,7 @@ PATH
|
|
15
15
|
parser (~> 2.7.0.2)
|
16
16
|
procto (~> 0.0.2)
|
17
17
|
unparser (~> 0.4.6)
|
18
|
+
variable (~> 0.0.1)
|
18
19
|
|
19
20
|
GEM
|
20
21
|
remote: https://rubygems.org/
|
@@ -142,6 +143,8 @@ GEM
|
|
142
143
|
equalizer (~> 0.0.9)
|
143
144
|
parser (>= 2.6.5)
|
144
145
|
procto (~> 0.0.2)
|
146
|
+
variable (0.0.1)
|
147
|
+
equalizer (~> 0.0.11)
|
145
148
|
virtus (1.0.5)
|
146
149
|
axiom-types (~> 0.1)
|
147
150
|
coercible (~> 1.0)
|
data/lib/mutant.rb
CHANGED
@@ -21,6 +21,7 @@ require 'set'
|
|
21
21
|
require 'singleton'
|
22
22
|
require 'stringio'
|
23
23
|
require 'unparser'
|
24
|
+
require 'variable'
|
24
25
|
require 'yaml'
|
25
26
|
|
26
27
|
# This setting is done to make errors within the parallel
|
@@ -185,7 +186,6 @@ require 'mutant/reporter/cli/format'
|
|
185
186
|
require 'mutant/repository'
|
186
187
|
require 'mutant/repository/diff'
|
187
188
|
require 'mutant/repository/diff/ranges'
|
188
|
-
require 'mutant/variable'
|
189
189
|
require 'mutant/warnings'
|
190
190
|
require 'mutant/zombifier'
|
191
191
|
require 'mutant/range'
|
data/lib/mutant/license.rb
CHANGED
data/lib/mutant/parallel.rb
CHANGED
data/lib/mutant/version.rb
CHANGED
data/mutant.gemspec
CHANGED
@@ -34,6 +34,7 @@ Gem::Specification.new do |gem|
|
|
34
34
|
gem.add_runtime_dependency('parser', '~> 2.7.0.2')
|
35
35
|
gem.add_runtime_dependency('procto', '~> 0.0.2')
|
36
36
|
gem.add_runtime_dependency('unparser', '~> 0.4.6')
|
37
|
+
gem.add_runtime_dependency('variable', '~> 0.0.1')
|
37
38
|
|
38
39
|
gem.add_development_dependency('devtools', '~> 0.1.25')
|
39
40
|
gem.add_development_dependency('parallel', '~> 1.3')
|
data/spec/integrations.yml
CHANGED
@@ -2,13 +2,14 @@
|
|
2
2
|
- name: rubyspec
|
3
3
|
namespace: Rubyspec
|
4
4
|
repo_uri: 'https://github.com/ruby/rubyspec.git'
|
5
|
-
repo_ref:
|
5
|
+
repo_ref: 249a36c2e9fcddbb208a0d618d05f6bd9a64fd17
|
6
6
|
integration: mspec
|
7
7
|
mutation_coverage: false
|
8
8
|
mutation_generation: true
|
9
9
|
exclude:
|
10
10
|
- command_line/fixtures/bad_syntax.rb
|
11
11
|
- command_line/fixtures/freeze_flag_required_diff_enc.rb
|
12
|
+
- core/file/stat_spec.rb
|
12
13
|
- core/kernel/shared/sprintf_encoding.rb
|
13
14
|
- core/module/fixtures/autoload_empty.rb
|
14
15
|
- core/module/fixtures/autoload_never_set.rb
|
@@ -26,6 +27,7 @@
|
|
26
27
|
- language/predefined/fixtures/data_only.rb
|
27
28
|
- language/source_encoding_spec.rb
|
28
29
|
- library/base64/decode64_spec.rb
|
30
|
+
- library/cgi/escapeHTML_spec.rb
|
29
31
|
- security/cve_2010_1330_spec.rb
|
30
32
|
- name: regexp_parser
|
31
33
|
namespace: Regexp
|
@@ -89,7 +89,7 @@ RSpec.describe Mutant::License do
|
|
89
89
|
|
90
90
|
expect(stderr)
|
91
91
|
.to have_received(:puts)
|
92
|
-
.with('[Mutant-License-Error]: Soft fail, continuing in
|
92
|
+
.with('[Mutant-License-Error]: Soft fail, continuing in 40 seconds')
|
93
93
|
.ordered
|
94
94
|
|
95
95
|
expect(stderr)
|
@@ -104,7 +104,7 @@ RSpec.describe Mutant::License do
|
|
104
104
|
|
105
105
|
expect(kernel)
|
106
106
|
.to have_received(:sleep)
|
107
|
-
.with(
|
107
|
+
.with(40)
|
108
108
|
.ordered
|
109
109
|
end
|
110
110
|
end
|
@@ -16,15 +16,15 @@ RSpec.describe Mutant::Parallel::Driver do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
let(:var_active_jobs) do
|
19
|
-
instance_double(
|
19
|
+
instance_double(Variable::IVar, 'active jobs')
|
20
20
|
end
|
21
21
|
|
22
22
|
let(:var_final) do
|
23
|
-
instance_double(
|
23
|
+
instance_double(Variable::IVar, 'final')
|
24
24
|
end
|
25
25
|
|
26
26
|
let(:var_sink) do
|
27
|
-
instance_double(
|
27
|
+
instance_double(Variable::IVar, 'sink')
|
28
28
|
end
|
29
29
|
|
30
30
|
subject do
|
@@ -64,7 +64,7 @@ RSpec.describe Mutant::Parallel::Driver do
|
|
64
64
|
receiver: var_final,
|
65
65
|
selector: :take_timeout,
|
66
66
|
arguments: [timeout],
|
67
|
-
reaction: { return:
|
67
|
+
reaction: { return: Variable.const_get(:Result)::Timeout.new }
|
68
68
|
},
|
69
69
|
{
|
70
70
|
receiver: var_active_jobs,
|
@@ -31,23 +31,23 @@ RSpec.describe Mutant::Parallel::Worker do
|
|
31
31
|
end
|
32
32
|
|
33
33
|
let(:var_active_jobs) do
|
34
|
-
instance_double(
|
34
|
+
instance_double(Variable::IVar, 'active jobs')
|
35
35
|
end
|
36
36
|
|
37
37
|
let(:var_final) do
|
38
|
-
instance_double(
|
38
|
+
instance_double(Variable::IVar, 'final')
|
39
39
|
end
|
40
40
|
|
41
41
|
let(:var_running) do
|
42
|
-
instance_double(
|
42
|
+
instance_double(Variable::MVar, 'running')
|
43
43
|
end
|
44
44
|
|
45
45
|
let(:var_sink) do
|
46
|
-
instance_double(
|
46
|
+
instance_double(Variable::IVar, 'sink')
|
47
47
|
end
|
48
48
|
|
49
49
|
let(:var_source) do
|
50
|
-
instance_double(
|
50
|
+
instance_double(Variable::IVar, 'source')
|
51
51
|
end
|
52
52
|
|
53
53
|
subject do
|
@@ -30,28 +30,28 @@ RSpec.describe Mutant::Parallel do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
let(:var_active_jobs) do
|
33
|
-
instance_double(
|
33
|
+
instance_double(Variable::IVar, 'active jobs')
|
34
34
|
end
|
35
35
|
|
36
36
|
let(:var_final) do
|
37
|
-
instance_double(
|
37
|
+
instance_double(Variable::IVar, 'final')
|
38
38
|
end
|
39
39
|
|
40
40
|
let(:var_running) do
|
41
|
-
instance_double(
|
41
|
+
instance_double(Variable::MVar, 'running')
|
42
42
|
end
|
43
43
|
|
44
44
|
let(:var_sink) do
|
45
|
-
instance_double(
|
45
|
+
instance_double(Variable::IVar, 'sink')
|
46
46
|
end
|
47
47
|
|
48
48
|
let(:var_source) do
|
49
|
-
instance_double(
|
49
|
+
instance_double(Variable::IVar, 'source')
|
50
50
|
end
|
51
51
|
|
52
52
|
def ivar(value, **attributes)
|
53
53
|
{
|
54
|
-
receiver:
|
54
|
+
receiver: Variable::IVar,
|
55
55
|
selector: :new,
|
56
56
|
arguments: [
|
57
57
|
condition_variable: condition_variable,
|
@@ -63,7 +63,7 @@ RSpec.describe Mutant::Parallel do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
def mvar(*arguments)
|
66
|
-
ivar(*arguments).merge(receiver:
|
66
|
+
ivar(*arguments).merge(receiver: Variable::MVar)
|
67
67
|
end
|
68
68
|
|
69
69
|
let(:raw_expectations) do
|
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.9.
|
4
|
+
version: 0.9.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: 2020-
|
11
|
+
date: 2020-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: abstract_type
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: 0.4.6
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: variable
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - "~>"
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: 0.0.1
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - "~>"
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: 0.0.1
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
name: devtools
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -409,7 +423,6 @@ files:
|
|
409
423
|
- lib/mutant/timer.rb
|
410
424
|
- lib/mutant/transform.rb
|
411
425
|
- lib/mutant/util.rb
|
412
|
-
- lib/mutant/variable.rb
|
413
426
|
- lib/mutant/version.rb
|
414
427
|
- lib/mutant/warnings.rb
|
415
428
|
- lib/mutant/zombifier.rb
|
@@ -594,7 +607,6 @@ files:
|
|
594
607
|
- spec/unit/mutant/transform/primitive_spec.rb
|
595
608
|
- spec/unit/mutant/transform/sequence_spec.rb
|
596
609
|
- spec/unit/mutant/util/one_spec.rb
|
597
|
-
- spec/unit/mutant/variable_spec.rb
|
598
610
|
- spec/unit/mutant/warnings_spec.rb
|
599
611
|
- spec/unit/mutant/world_spec.rb
|
600
612
|
- spec/unit/mutant/zombifier_spec.rb
|
@@ -625,7 +637,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
625
637
|
- !ruby/object:Gem::Version
|
626
638
|
version: '0'
|
627
639
|
requirements: []
|
628
|
-
rubygems_version: 3.
|
640
|
+
rubygems_version: 3.1.2
|
629
641
|
signing_key:
|
630
642
|
specification_version: 4
|
631
643
|
summary: ''
|
@@ -730,7 +742,6 @@ test_files:
|
|
730
742
|
- spec/unit/mutant/transform/primitive_spec.rb
|
731
743
|
- spec/unit/mutant/transform/sequence_spec.rb
|
732
744
|
- spec/unit/mutant/util/one_spec.rb
|
733
|
-
- spec/unit/mutant/variable_spec.rb
|
734
745
|
- spec/unit/mutant/warnings_spec.rb
|
735
746
|
- spec/unit/mutant/world_spec.rb
|
736
747
|
- spec/unit/mutant/zombifier_spec.rb
|
data/lib/mutant/variable.rb
DELETED
@@ -1,282 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
# Lightweight shared variables
|
5
|
-
#
|
6
|
-
# ignore :reek:TooManyMethods
|
7
|
-
class Variable
|
8
|
-
EMPTY = Class.new do
|
9
|
-
const_set(:INSPECT, 'Mutant::Variable::EMPTY')
|
10
|
-
end.new.freeze
|
11
|
-
|
12
|
-
TIMEOUT = Class.new do
|
13
|
-
const_set(:INSPECT, 'Mutant::Variable::TIMEOUT')
|
14
|
-
end.new.freeze
|
15
|
-
|
16
|
-
# Result of operation that may time out
|
17
|
-
class Result
|
18
|
-
include AbstractType, Adamantium::Flat
|
19
|
-
|
20
|
-
# Test if take resulted in a timeout
|
21
|
-
#
|
22
|
-
# @return [Boolean]
|
23
|
-
#
|
24
|
-
# @api private
|
25
|
-
def timeout?
|
26
|
-
instance_of?(Timeout)
|
27
|
-
end
|
28
|
-
|
29
|
-
abstract_method :value
|
30
|
-
|
31
|
-
# Instance returned on timeouts
|
32
|
-
class Timeout < self
|
33
|
-
include Equalizer.new
|
34
|
-
|
35
|
-
INSTANCE = new
|
36
|
-
|
37
|
-
# Construct new object
|
38
|
-
#
|
39
|
-
# @return [Timeout]
|
40
|
-
def self.new
|
41
|
-
INSTANCE
|
42
|
-
end
|
43
|
-
end # Timeout
|
44
|
-
|
45
|
-
# Instance returned without timeouts
|
46
|
-
class Value < self
|
47
|
-
include Concord::Public.new(:value)
|
48
|
-
end # Value
|
49
|
-
end # Result
|
50
|
-
|
51
|
-
private_constant(*constants(false))
|
52
|
-
|
53
|
-
# Initialize object
|
54
|
-
#
|
55
|
-
# @param [Object] value
|
56
|
-
# the initial value
|
57
|
-
#
|
58
|
-
# @return [undefined]
|
59
|
-
def initialize(condition_variable:, mutex:, value: EMPTY)
|
60
|
-
@full = condition_variable.new
|
61
|
-
@mutex = mutex.new
|
62
|
-
@value = value
|
63
|
-
end
|
64
|
-
|
65
|
-
# Take value from mvar, block on empty
|
66
|
-
#
|
67
|
-
# @return [Object]
|
68
|
-
def take
|
69
|
-
synchronize do
|
70
|
-
wait_full
|
71
|
-
perform_take
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
# Take value from mvar, with timeout
|
76
|
-
#
|
77
|
-
# @param [Float] Timeout
|
78
|
-
#
|
79
|
-
# @return [Result::Timeout]
|
80
|
-
# in case take resulted in a timeout
|
81
|
-
#
|
82
|
-
# @return [Result::Value]
|
83
|
-
# in case take resulted in a value
|
84
|
-
def take_timeout(timeout)
|
85
|
-
synchronize do
|
86
|
-
if wait_timeout(@full, timeout, &method(:full?))
|
87
|
-
Result::Timeout.new
|
88
|
-
else
|
89
|
-
Result::Value.new(perform_take)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
# Read value from variable
|
95
|
-
#
|
96
|
-
# @return [Object]
|
97
|
-
# the contents of the mvar
|
98
|
-
def read
|
99
|
-
synchronize do
|
100
|
-
wait_full
|
101
|
-
@value
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Try put value into the variable, non blocking
|
106
|
-
#
|
107
|
-
# @param [Object] value
|
108
|
-
#
|
109
|
-
# @return [self]
|
110
|
-
def try_put(value)
|
111
|
-
synchronize do
|
112
|
-
perform_put(value) if empty?
|
113
|
-
end
|
114
|
-
|
115
|
-
self
|
116
|
-
end
|
117
|
-
|
118
|
-
# Execute block with value, blocking
|
119
|
-
#
|
120
|
-
# @yield [Object]
|
121
|
-
#
|
122
|
-
# @return [Object]
|
123
|
-
# the blocks return value
|
124
|
-
def with
|
125
|
-
synchronize do
|
126
|
-
wait_full
|
127
|
-
yield @value
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
private
|
132
|
-
|
133
|
-
# Perform the put
|
134
|
-
#
|
135
|
-
# @param [Object] value
|
136
|
-
def perform_put(value)
|
137
|
-
(@value = value).tap { @full.signal }
|
138
|
-
end
|
139
|
-
|
140
|
-
# Execute block under mutex
|
141
|
-
#
|
142
|
-
# @return [self]
|
143
|
-
def synchronize(&block)
|
144
|
-
@mutex.synchronize(&block)
|
145
|
-
end
|
146
|
-
|
147
|
-
# Wait for block predicate
|
148
|
-
#
|
149
|
-
# @param [ConditionVariable] event
|
150
|
-
#
|
151
|
-
# @return [undefined]
|
152
|
-
def wait(event)
|
153
|
-
event.wait(@mutex) until yield
|
154
|
-
end
|
155
|
-
|
156
|
-
# Wait with timeout for block predicate
|
157
|
-
#
|
158
|
-
# @param [ConditionVariable] event
|
159
|
-
#
|
160
|
-
# @return [Boolean]
|
161
|
-
# if wait was terminated due a timeout
|
162
|
-
#
|
163
|
-
# @return [undefined]
|
164
|
-
# otherwise
|
165
|
-
def wait_timeout(event, timeout)
|
166
|
-
loop do
|
167
|
-
break true if timeout <= 0
|
168
|
-
break if yield
|
169
|
-
timeout -= Timer.elapsed { event.wait(@mutex, timeout) }
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
# Wait till mvar is full
|
174
|
-
#
|
175
|
-
# @return [undefined]
|
176
|
-
def wait_full
|
177
|
-
wait(@full, &method(:full?))
|
178
|
-
end
|
179
|
-
|
180
|
-
# Test if state is full
|
181
|
-
#
|
182
|
-
# @return [Boolean]
|
183
|
-
def full?
|
184
|
-
!empty?
|
185
|
-
end
|
186
|
-
|
187
|
-
# Test if state is empty
|
188
|
-
#
|
189
|
-
# @return [Boolean]
|
190
|
-
def empty?
|
191
|
-
@value.equal?(EMPTY)
|
192
|
-
end
|
193
|
-
|
194
|
-
# Shared variable that can be written at most once
|
195
|
-
#
|
196
|
-
# ignore :reek:InstanceVariableAssumption
|
197
|
-
class IVar < self
|
198
|
-
|
199
|
-
# Exception raised on ivar errors
|
200
|
-
class Error < RuntimeError; end
|
201
|
-
|
202
|
-
# Put valie into the mvar, raises if already full
|
203
|
-
#
|
204
|
-
# @param [Object] value
|
205
|
-
#
|
206
|
-
# @return [self]
|
207
|
-
#
|
208
|
-
# @raise Error
|
209
|
-
# if already full
|
210
|
-
def put(value)
|
211
|
-
synchronize do
|
212
|
-
fail Error, 'is immutable' if full?
|
213
|
-
perform_put(value)
|
214
|
-
end
|
215
|
-
|
216
|
-
self
|
217
|
-
end
|
218
|
-
|
219
|
-
private
|
220
|
-
|
221
|
-
# Perform take operation
|
222
|
-
#
|
223
|
-
# @return [Object]
|
224
|
-
def perform_take
|
225
|
-
@value
|
226
|
-
end
|
227
|
-
end # IVar
|
228
|
-
|
229
|
-
# Shared variable that can be written multiple times
|
230
|
-
#
|
231
|
-
# ignore :reek:InstanceVariableAssumption
|
232
|
-
class MVar < self
|
233
|
-
|
234
|
-
# Initialize object
|
235
|
-
#
|
236
|
-
# @param [Object] value
|
237
|
-
# the initial value
|
238
|
-
#
|
239
|
-
# @return [undefined]
|
240
|
-
def initialize(condition_variable:, mutex:, value: EMPTY)
|
241
|
-
super
|
242
|
-
@empty = condition_variable.new
|
243
|
-
end
|
244
|
-
|
245
|
-
# Put value into mvar, block on full
|
246
|
-
#
|
247
|
-
# @param [Object] value
|
248
|
-
#
|
249
|
-
# @return [self]
|
250
|
-
def put(value)
|
251
|
-
synchronize do
|
252
|
-
wait(@empty, &method(:empty?))
|
253
|
-
perform_put(value)
|
254
|
-
end
|
255
|
-
|
256
|
-
self
|
257
|
-
end
|
258
|
-
|
259
|
-
# Modify mvar
|
260
|
-
#
|
261
|
-
# @return [Object]
|
262
|
-
def modify
|
263
|
-
synchronize do
|
264
|
-
wait_full
|
265
|
-
perform_put(yield(@value))
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
private
|
270
|
-
|
271
|
-
# Empty the mvar
|
272
|
-
#
|
273
|
-
# @return [Object]
|
274
|
-
def perform_take
|
275
|
-
@value.tap do
|
276
|
-
@value = EMPTY
|
277
|
-
@empty.signal
|
278
|
-
end
|
279
|
-
end
|
280
|
-
end # MVar
|
281
|
-
end # Variable
|
282
|
-
end # Mutant
|
@@ -1,618 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module MutantSpec
|
4
|
-
module VariableHelper
|
5
|
-
def empty
|
6
|
-
described_class.new(
|
7
|
-
condition_variable: condition_variable_class,
|
8
|
-
mutex: mutex_class
|
9
|
-
)
|
10
|
-
end
|
11
|
-
|
12
|
-
def full(value)
|
13
|
-
described_class.new(
|
14
|
-
condition_variable: condition_variable_class,
|
15
|
-
mutex: mutex_class,
|
16
|
-
value: value
|
17
|
-
)
|
18
|
-
end
|
19
|
-
|
20
|
-
# rubocop:disable Metrics/AbcSize
|
21
|
-
# rubocop:disable Metrics/MethodLength
|
22
|
-
def self.shared_setup
|
23
|
-
lambda do |_host|
|
24
|
-
let(:condition_variable_class) { class_double(ConditionVariable) }
|
25
|
-
let(:expected_result) { value }
|
26
|
-
let(:full_condition) { instance_double(ConditionVariable, 'full') }
|
27
|
-
let(:mutex) { instance_double(Mutex) }
|
28
|
-
let(:mutex_class) { class_double(Mutex) }
|
29
|
-
let(:value) { instance_double(Object, 'value') }
|
30
|
-
|
31
|
-
let(:synchronize) do
|
32
|
-
{
|
33
|
-
receiver: mutex,
|
34
|
-
selector: :synchronize,
|
35
|
-
reaction: { yields: [] }
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
|
-
let(:signal_full) do
|
40
|
-
{
|
41
|
-
receiver: full_condition,
|
42
|
-
selector: :signal
|
43
|
-
}
|
44
|
-
end
|
45
|
-
|
46
|
-
let(:put) do
|
47
|
-
{
|
48
|
-
receiver: full_condition,
|
49
|
-
selector: :wait,
|
50
|
-
arguments: [mutex],
|
51
|
-
reaction: { execute: -> { subject.put(value) } }
|
52
|
-
}
|
53
|
-
end
|
54
|
-
|
55
|
-
let(:wait_empty) do
|
56
|
-
{
|
57
|
-
receiver: empty_condition,
|
58
|
-
selector: :wait,
|
59
|
-
arguments: [mutex]
|
60
|
-
}
|
61
|
-
end
|
62
|
-
|
63
|
-
let(:wait_full) do
|
64
|
-
{
|
65
|
-
receiver: full_condition,
|
66
|
-
selector: :wait,
|
67
|
-
arguments: [mutex]
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
let(:signal_empty) do
|
72
|
-
{
|
73
|
-
receiver: empty_condition,
|
74
|
-
selector: :signal
|
75
|
-
}
|
76
|
-
end
|
77
|
-
|
78
|
-
shared_examples 'consumes events' do
|
79
|
-
specify do
|
80
|
-
verify_events do
|
81
|
-
expect(apply).to eql(expected_result)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
RSpec.describe Mutant::Variable::IVar do
|
91
|
-
include MutantSpec::VariableHelper
|
92
|
-
|
93
|
-
class_eval(&MutantSpec::VariableHelper.shared_setup)
|
94
|
-
|
95
|
-
subject { empty }
|
96
|
-
|
97
|
-
let(:setup) do
|
98
|
-
[
|
99
|
-
{
|
100
|
-
receiver: condition_variable_class,
|
101
|
-
selector: :new,
|
102
|
-
reaction: { return: full_condition }
|
103
|
-
},
|
104
|
-
{
|
105
|
-
receiver: mutex_class,
|
106
|
-
selector: :new,
|
107
|
-
reaction: { return: mutex }
|
108
|
-
},
|
109
|
-
synchronize
|
110
|
-
]
|
111
|
-
end
|
112
|
-
|
113
|
-
describe '#take' do
|
114
|
-
def apply
|
115
|
-
subject.take
|
116
|
-
end
|
117
|
-
|
118
|
-
context 'when ivar is initially full' do
|
119
|
-
subject { full(value) }
|
120
|
-
|
121
|
-
let(:raw_expectations) { setup }
|
122
|
-
|
123
|
-
include_examples 'consumes events'
|
124
|
-
end
|
125
|
-
|
126
|
-
context 'when ivar is initially empty' do
|
127
|
-
let(:raw_expectations) do
|
128
|
-
[
|
129
|
-
*setup,
|
130
|
-
put,
|
131
|
-
synchronize,
|
132
|
-
signal_full
|
133
|
-
]
|
134
|
-
end
|
135
|
-
|
136
|
-
include_examples 'consumes events'
|
137
|
-
end
|
138
|
-
end
|
139
|
-
|
140
|
-
describe '#take_timeout' do
|
141
|
-
def apply
|
142
|
-
subject.take_timeout(1.0)
|
143
|
-
end
|
144
|
-
|
145
|
-
context 'when ivar is initially full' do
|
146
|
-
subject { full(value) }
|
147
|
-
|
148
|
-
let(:raw_expectations) { setup }
|
149
|
-
|
150
|
-
let(:expected_result) do
|
151
|
-
Mutant::Variable.const_get(:Result)::Value.new(value)
|
152
|
-
end
|
153
|
-
|
154
|
-
include_examples 'consumes events'
|
155
|
-
end
|
156
|
-
|
157
|
-
context 'when ivar is initially empty' do
|
158
|
-
def wait(time)
|
159
|
-
{
|
160
|
-
receiver: full_condition,
|
161
|
-
selector: :wait,
|
162
|
-
arguments: [mutex, time]
|
163
|
-
}
|
164
|
-
end
|
165
|
-
|
166
|
-
def elapsed(time)
|
167
|
-
{
|
168
|
-
receiver: Mutant::Timer,
|
169
|
-
selector: :elapsed,
|
170
|
-
reaction: { yields: [], return: time }
|
171
|
-
}
|
172
|
-
end
|
173
|
-
|
174
|
-
context 'and timeout occurs before value is put' do
|
175
|
-
let(:expected_result) do
|
176
|
-
Mutant::Variable.const_get(:Result)::Timeout.new
|
177
|
-
end
|
178
|
-
|
179
|
-
context 'wait exactly runs to zero left time on the clock' do
|
180
|
-
let(:raw_expectations) do
|
181
|
-
[
|
182
|
-
*setup,
|
183
|
-
elapsed(0.5),
|
184
|
-
wait(1.0),
|
185
|
-
elapsed(0.5),
|
186
|
-
wait(0.5)
|
187
|
-
]
|
188
|
-
end
|
189
|
-
|
190
|
-
include_examples 'consumes events'
|
191
|
-
end
|
192
|
-
|
193
|
-
context 'wait overruns timeout' do
|
194
|
-
let(:raw_expectations) do
|
195
|
-
[
|
196
|
-
*setup,
|
197
|
-
elapsed(1.5),
|
198
|
-
wait(1.0)
|
199
|
-
]
|
200
|
-
end
|
201
|
-
|
202
|
-
include_examples 'consumes events'
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
context 'and put occurs before timeout' do
|
207
|
-
let(:expected_result) do
|
208
|
-
Mutant::Variable.const_get(:Result)::Value.new(value)
|
209
|
-
end
|
210
|
-
|
211
|
-
let(:raw_expectations) do
|
212
|
-
[
|
213
|
-
*setup,
|
214
|
-
elapsed(0.5),
|
215
|
-
wait(1.0).merge(reaction: { execute: -> { subject.put(value) } }),
|
216
|
-
synchronize,
|
217
|
-
signal_full
|
218
|
-
]
|
219
|
-
end
|
220
|
-
|
221
|
-
include_examples 'consumes events'
|
222
|
-
end
|
223
|
-
end
|
224
|
-
end
|
225
|
-
|
226
|
-
describe '#put' do
|
227
|
-
def apply
|
228
|
-
subject.put(value)
|
229
|
-
end
|
230
|
-
|
231
|
-
context 'when ivar is initially empty' do
|
232
|
-
context 'when not reading result' do
|
233
|
-
let(:expected_result) { subject }
|
234
|
-
|
235
|
-
let(:raw_expectations) do
|
236
|
-
[
|
237
|
-
*setup,
|
238
|
-
signal_full
|
239
|
-
]
|
240
|
-
end
|
241
|
-
|
242
|
-
include_examples 'consumes events'
|
243
|
-
end
|
244
|
-
|
245
|
-
context 'when reading result back' do
|
246
|
-
let(:expected_result) { value }
|
247
|
-
|
248
|
-
def apply
|
249
|
-
super
|
250
|
-
subject.read
|
251
|
-
end
|
252
|
-
|
253
|
-
let(:raw_expectations) do
|
254
|
-
[
|
255
|
-
*setup,
|
256
|
-
signal_full,
|
257
|
-
synchronize
|
258
|
-
]
|
259
|
-
end
|
260
|
-
|
261
|
-
include_examples 'consumes events'
|
262
|
-
end
|
263
|
-
end
|
264
|
-
|
265
|
-
context 'when ivar is initially full' do
|
266
|
-
subject { full(value) }
|
267
|
-
|
268
|
-
let(:raw_expectations) { setup }
|
269
|
-
|
270
|
-
it 'raises expected exception' do
|
271
|
-
verify_events do
|
272
|
-
expect { apply }.to raise_error(Mutant::Variable::IVar::Error, 'is immutable')
|
273
|
-
end
|
274
|
-
end
|
275
|
-
end
|
276
|
-
end
|
277
|
-
|
278
|
-
describe '#try_put' do
|
279
|
-
def apply
|
280
|
-
subject.try_put(value)
|
281
|
-
end
|
282
|
-
|
283
|
-
let(:expected_result) { subject }
|
284
|
-
|
285
|
-
context 'when ivar is initially empty' do
|
286
|
-
let(:raw_expectations) do
|
287
|
-
[
|
288
|
-
*setup,
|
289
|
-
signal_full
|
290
|
-
]
|
291
|
-
end
|
292
|
-
|
293
|
-
include_examples 'consumes events'
|
294
|
-
|
295
|
-
context 'reading the put value' do
|
296
|
-
let(:expected_result) { value }
|
297
|
-
|
298
|
-
let(:raw_expectations) do
|
299
|
-
[
|
300
|
-
*super(),
|
301
|
-
synchronize
|
302
|
-
]
|
303
|
-
end
|
304
|
-
|
305
|
-
def apply
|
306
|
-
super
|
307
|
-
subject.read
|
308
|
-
end
|
309
|
-
|
310
|
-
include_examples 'consumes events'
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
context 'when ivar is initially full' do
|
315
|
-
subject { full(value) }
|
316
|
-
|
317
|
-
let(:raw_expectations) { setup }
|
318
|
-
|
319
|
-
include_examples 'consumes events'
|
320
|
-
end
|
321
|
-
end
|
322
|
-
|
323
|
-
describe '#read' do
|
324
|
-
def apply
|
325
|
-
subject.read
|
326
|
-
end
|
327
|
-
|
328
|
-
context 'when ivar is initially empty' do
|
329
|
-
let(:raw_expectations) do
|
330
|
-
[
|
331
|
-
*setup,
|
332
|
-
wait_full.merge(reaction: { execute: -> { subject.put(value) } }),
|
333
|
-
synchronize,
|
334
|
-
signal_full
|
335
|
-
]
|
336
|
-
end
|
337
|
-
|
338
|
-
include_examples 'consumes events'
|
339
|
-
end
|
340
|
-
|
341
|
-
context 'when ivar is initially full' do
|
342
|
-
subject { full(value) }
|
343
|
-
|
344
|
-
let(:raw_expectations) { setup }
|
345
|
-
|
346
|
-
include_examples 'consumes events'
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
describe '#with' do
|
351
|
-
def apply
|
352
|
-
subject.with do |value|
|
353
|
-
@value = value
|
354
|
-
end
|
355
|
-
end
|
356
|
-
|
357
|
-
before { @value = nil }
|
358
|
-
|
359
|
-
context 'when ivar is initially full' do
|
360
|
-
subject { full(value) }
|
361
|
-
|
362
|
-
let(:raw_expectations) { setup }
|
363
|
-
|
364
|
-
include_examples 'consumes events'
|
365
|
-
|
366
|
-
it 'should yield value' do
|
367
|
-
verify_events do
|
368
|
-
expect { apply }.to change { @value }.from(nil).to(value)
|
369
|
-
end
|
370
|
-
end
|
371
|
-
end
|
372
|
-
|
373
|
-
context 'when ivar is initially empty' do
|
374
|
-
subject { empty }
|
375
|
-
|
376
|
-
let(:raw_expectations) do
|
377
|
-
[
|
378
|
-
*setup,
|
379
|
-
put,
|
380
|
-
synchronize,
|
381
|
-
signal_full
|
382
|
-
]
|
383
|
-
end
|
384
|
-
|
385
|
-
include_examples 'consumes events'
|
386
|
-
|
387
|
-
it 'should yield value' do
|
388
|
-
verify_events do
|
389
|
-
expect { apply }.to change { @value }.from(nil).to(value)
|
390
|
-
end
|
391
|
-
end
|
392
|
-
end
|
393
|
-
end
|
394
|
-
end
|
395
|
-
|
396
|
-
describe Mutant::Variable::MVar do
|
397
|
-
include MutantSpec::VariableHelper
|
398
|
-
|
399
|
-
class_eval(&MutantSpec::VariableHelper.shared_setup)
|
400
|
-
|
401
|
-
subject { empty }
|
402
|
-
|
403
|
-
let(:empty_condition) { instance_double(ConditionVariable, 'empty') }
|
404
|
-
|
405
|
-
let(:setup) do
|
406
|
-
[
|
407
|
-
{
|
408
|
-
receiver: condition_variable_class,
|
409
|
-
selector: :new,
|
410
|
-
reaction: { return: full_condition }
|
411
|
-
},
|
412
|
-
{
|
413
|
-
receiver: mutex_class,
|
414
|
-
selector: :new,
|
415
|
-
reaction: { return: mutex }
|
416
|
-
},
|
417
|
-
{
|
418
|
-
receiver: condition_variable_class,
|
419
|
-
selector: :new,
|
420
|
-
reaction: { return: empty_condition }
|
421
|
-
},
|
422
|
-
synchronize
|
423
|
-
]
|
424
|
-
end
|
425
|
-
|
426
|
-
describe '#put' do
|
427
|
-
def apply
|
428
|
-
subject.put(value)
|
429
|
-
end
|
430
|
-
|
431
|
-
context 'when ivar is initially empty' do
|
432
|
-
context 'when not reading result' do
|
433
|
-
let(:expected_result) { subject }
|
434
|
-
|
435
|
-
let(:raw_expectations) do
|
436
|
-
[
|
437
|
-
*setup,
|
438
|
-
signal_full
|
439
|
-
]
|
440
|
-
end
|
441
|
-
|
442
|
-
include_examples 'consumes events'
|
443
|
-
end
|
444
|
-
|
445
|
-
context 'when reading result back' do
|
446
|
-
let(:expected_result) { value }
|
447
|
-
|
448
|
-
def apply
|
449
|
-
super
|
450
|
-
subject.read
|
451
|
-
end
|
452
|
-
|
453
|
-
let(:raw_expectations) do
|
454
|
-
[
|
455
|
-
*setup,
|
456
|
-
signal_full,
|
457
|
-
synchronize
|
458
|
-
]
|
459
|
-
end
|
460
|
-
|
461
|
-
include_examples 'consumes events'
|
462
|
-
end
|
463
|
-
end
|
464
|
-
|
465
|
-
context 'when ivar is initially full' do
|
466
|
-
context 'when not reading result' do
|
467
|
-
subject { full(value) }
|
468
|
-
|
469
|
-
let(:expected_result) { subject }
|
470
|
-
|
471
|
-
let(:raw_expectations) do
|
472
|
-
[
|
473
|
-
*setup,
|
474
|
-
wait_empty.merge(reaction: { execute: -> { subject.take } }),
|
475
|
-
synchronize,
|
476
|
-
signal_empty,
|
477
|
-
signal_full
|
478
|
-
]
|
479
|
-
end
|
480
|
-
|
481
|
-
include_examples 'consumes events'
|
482
|
-
end
|
483
|
-
|
484
|
-
context 'when reading result back' do
|
485
|
-
subject { full(value) }
|
486
|
-
|
487
|
-
def apply
|
488
|
-
super
|
489
|
-
subject.read
|
490
|
-
end
|
491
|
-
|
492
|
-
let(:expected_result) { value }
|
493
|
-
|
494
|
-
let(:raw_expectations) do
|
495
|
-
[
|
496
|
-
*setup,
|
497
|
-
wait_empty.merge(reaction: { execute: -> { subject.take } }),
|
498
|
-
synchronize,
|
499
|
-
signal_empty,
|
500
|
-
signal_full,
|
501
|
-
synchronize
|
502
|
-
]
|
503
|
-
end
|
504
|
-
|
505
|
-
include_examples 'consumes events'
|
506
|
-
end
|
507
|
-
end
|
508
|
-
end
|
509
|
-
|
510
|
-
describe '#modify' do
|
511
|
-
let(:expected_result) { 1 }
|
512
|
-
let(:value) { 0 }
|
513
|
-
|
514
|
-
def apply
|
515
|
-
subject.modify(&:succ)
|
516
|
-
end
|
517
|
-
|
518
|
-
context 'when ivar is initially empty' do
|
519
|
-
let(:raw_expectations) do
|
520
|
-
[
|
521
|
-
*setup,
|
522
|
-
wait_full.merge(reaction: { execute: -> { subject.put(value) } }),
|
523
|
-
synchronize,
|
524
|
-
signal_full,
|
525
|
-
signal_full
|
526
|
-
]
|
527
|
-
end
|
528
|
-
|
529
|
-
include_examples 'consumes events'
|
530
|
-
end
|
531
|
-
|
532
|
-
context 'when ivar is initially full' do
|
533
|
-
subject { full(value) }
|
534
|
-
|
535
|
-
let(:raw_expectations) do
|
536
|
-
[
|
537
|
-
*setup,
|
538
|
-
signal_full
|
539
|
-
]
|
540
|
-
end
|
541
|
-
|
542
|
-
include_examples 'consumes events'
|
543
|
-
end
|
544
|
-
end
|
545
|
-
|
546
|
-
describe '#take' do
|
547
|
-
def apply
|
548
|
-
subject.take
|
549
|
-
end
|
550
|
-
|
551
|
-
context 'when ivar is initially empty' do
|
552
|
-
let(:expected_result) { value }
|
553
|
-
|
554
|
-
let(:raw_expectations) do
|
555
|
-
[
|
556
|
-
*setup,
|
557
|
-
wait_full.merge(reaction: { execute: -> { subject.put(value) } }),
|
558
|
-
synchronize,
|
559
|
-
signal_full,
|
560
|
-
signal_empty
|
561
|
-
]
|
562
|
-
end
|
563
|
-
|
564
|
-
include_examples 'consumes events'
|
565
|
-
end
|
566
|
-
|
567
|
-
context 'when ivar is initially full' do
|
568
|
-
subject { full(value) }
|
569
|
-
|
570
|
-
let(:expected_result) { value }
|
571
|
-
|
572
|
-
let(:raw_expectations) do
|
573
|
-
[
|
574
|
-
*setup,
|
575
|
-
signal_empty
|
576
|
-
]
|
577
|
-
end
|
578
|
-
|
579
|
-
include_examples 'consumes events'
|
580
|
-
end
|
581
|
-
end
|
582
|
-
end
|
583
|
-
|
584
|
-
describe Mutant::Variable.const_get(:Result)::Value do
|
585
|
-
subject { described_class.new(nil) }
|
586
|
-
|
587
|
-
describe '#timeout?' do
|
588
|
-
def apply
|
589
|
-
subject.timeout?
|
590
|
-
end
|
591
|
-
|
592
|
-
it 'returns false' do
|
593
|
-
expect(apply).to be(false)
|
594
|
-
end
|
595
|
-
end
|
596
|
-
end
|
597
|
-
|
598
|
-
describe Mutant::Variable.const_get(:Result)::Timeout do
|
599
|
-
describe '.new' do
|
600
|
-
it 'is instance of timeout' do
|
601
|
-
expect(described_class.new.instance_of?(described_class)).to be(true)
|
602
|
-
end
|
603
|
-
|
604
|
-
it 'is idempotent' do
|
605
|
-
expect(described_class.new).to be(described_class.new)
|
606
|
-
end
|
607
|
-
end
|
608
|
-
|
609
|
-
describe '#timeout?' do
|
610
|
-
def apply
|
611
|
-
subject.timeout?
|
612
|
-
end
|
613
|
-
|
614
|
-
it 'returns true' do
|
615
|
-
expect(apply).to be(true)
|
616
|
-
end
|
617
|
-
end
|
618
|
-
end
|