mutant 0.9.3 → 0.9.8

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +121 -0
  3. data/Changelog.md +24 -0
  4. data/Gemfile +0 -15
  5. data/Gemfile.lock +56 -59
  6. data/Gemfile.shared +7 -0
  7. data/LICENSE +1 -1
  8. data/README.md +10 -1
  9. data/config/rubocop.yml +10 -3
  10. data/docs/commercial-support.md +14 -0
  11. data/lib/mutant.rb +4 -2
  12. data/lib/mutant/cli.rb +5 -5
  13. data/lib/mutant/integration.rb +1 -1
  14. data/lib/mutant/license.rb +2 -2
  15. data/lib/mutant/license/subscription/opensource.rb +1 -1
  16. data/lib/mutant/meta.rb +1 -3
  17. data/lib/mutant/meta/example/verification.rb +1 -1
  18. data/lib/mutant/mutator/node/generic.rb +0 -48
  19. data/lib/mutant/mutator/node/send.rb +1 -1
  20. data/lib/mutant/parallel.rb +1 -1
  21. data/lib/mutant/registry.rb +2 -7
  22. data/lib/mutant/reporter/cli/format.rb +1 -1
  23. data/lib/mutant/transform.rb +6 -5
  24. data/lib/mutant/version.rb +1 -1
  25. data/lib/mutant/zombifier.rb +2 -0
  26. data/mutant.gemspec +15 -13
  27. data/spec/integrations.yml +3 -1
  28. data/spec/support/corpus.rb +3 -3
  29. data/spec/support/ruby_vm.rb +1 -2
  30. data/spec/support/shared_context.rb +3 -3
  31. data/spec/support/xspec.rb +2 -2
  32. data/spec/unit/mutant/license_spec.rb +2 -2
  33. data/spec/unit/mutant/parallel/driver_spec.rb +4 -4
  34. data/spec/unit/mutant/parallel/worker_spec.rb +5 -5
  35. data/spec/unit/mutant/parallel_spec.rb +7 -7
  36. data/spec/unit/mutant/registry_spec.rb +52 -25
  37. data/spec/unit/mutant/repository/diff/ranges_spec.rb +2 -2
  38. metadata +44 -23
  39. data/.circleci/config.yml +0 -53
  40. data/lib/mutant/base.rb +0 -192
  41. data/lib/mutant/variable.rb +0 -282
  42. data/spec/unit/mutant/either_spec.rb +0 -247
  43. data/spec/unit/mutant/maybe_spec.rb +0 -60
  44. data/spec/unit/mutant/variable_spec.rb +0 -618
@@ -1,247 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Mutant::Either do
4
- describe '.wrap_error' do
5
- def apply
6
- described_class.wrap_error(error, &block)
7
- end
8
-
9
- let(:error) { TestError }
10
-
11
- class TestError < RuntimeError; end
12
-
13
- context 'when block returns' do
14
- let(:value) { instance_double(Object, 'value') }
15
- let(:block) { -> { value } }
16
-
17
- it 'returns right wrapping block value' do
18
- expect(apply).to eql(described_class::Right.new(value))
19
- end
20
- end
21
-
22
- context 'when block raises' do
23
- let(:exception) { error.new }
24
- let(:block) { -> { fail exception } }
25
-
26
- context 'with covered exception' do
27
- it 'returns left wrapping exception' do
28
- expect(apply).to eql(described_class::Left.new(exception))
29
- end
30
- end
31
-
32
- context 'with uncovered exception' do
33
- let(:exception) { StandardError.new }
34
-
35
- it 'returns raises error' do
36
- expect { apply }.to raise_error(StandardError)
37
- end
38
- end
39
- end
40
- end
41
- end
42
-
43
- RSpec.describe Mutant::Either::Left do
44
- subject { described_class.new(value) }
45
-
46
- let(:block_result) { instance_double(Object, 'block result') }
47
- let(:value) { instance_double(Object, 'value') }
48
- let(:yields) { [] }
49
-
50
- let(:block) do
51
- lambda do |value|
52
- yields << value
53
- block_result
54
- end
55
- end
56
-
57
- class TestError < RuntimeError; end
58
-
59
- describe '#fmap' do
60
- def apply
61
- subject.fmap(&block)
62
- end
63
-
64
- include_examples 'no block evaluation'
65
- include_examples 'requires block'
66
- include_examples 'returns self'
67
- end
68
-
69
- describe '#apply' do
70
- def apply
71
- subject.apply(&block)
72
- end
73
-
74
- include_examples 'no block evaluation'
75
- include_examples 'requires block'
76
- include_examples 'returns self'
77
- end
78
-
79
- describe '#from_left' do
80
- def apply
81
- subject.from_left(&block)
82
- end
83
-
84
- it 'returns left value' do
85
- expect(apply).to be(value)
86
- end
87
-
88
- include_examples 'no block evaluation'
89
- end
90
-
91
- describe '#from_right' do
92
- def apply
93
- subject.from_right(&block)
94
- end
95
-
96
- context 'without block' do
97
- let(:block) { nil }
98
-
99
- it 'raises RuntimeError error' do
100
- expect { apply }.to raise_error(
101
- RuntimeError,
102
- "Expected right value, got #{subject.inspect}"
103
- )
104
- end
105
- end
106
-
107
- context 'with block' do
108
- let(:yields) { [] }
109
- let(:block_return) { instance_double(Object, 'block-return') }
110
-
111
- let(:block) do
112
- lambda do |value|
113
- yields << value
114
- block_return
115
- end
116
- end
117
-
118
- it 'calls block with left value' do
119
- expect { apply }.to change(yields, :to_a).from([]).to([value])
120
- end
121
-
122
- it 'returns block value' do
123
- expect(apply).to be(block_return)
124
- end
125
- end
126
- end
127
-
128
- describe '#lmap' do
129
- def apply
130
- subject.lmap(&block)
131
- end
132
-
133
- include_examples 'requires block'
134
- include_examples 'Functor#fmap block evaluation'
135
- end
136
-
137
- describe '#either' do
138
- def apply
139
- subject.either(block, -> { fail })
140
- end
141
-
142
- include_examples '#apply block evaluation'
143
- end
144
- end
145
-
146
- RSpec.describe Mutant::Either::Right do
147
- subject { described_class.new(value) }
148
-
149
- let(:block_result) { instance_double(Object, 'block result') }
150
- let(:value) { instance_double(Object, 'value') }
151
- let(:yields) { [] }
152
-
153
- let(:block) do
154
- lambda do |value|
155
- yields << value
156
- block_result
157
- end
158
- end
159
-
160
- describe '#fmap' do
161
- def apply
162
- subject.fmap(&block)
163
- end
164
-
165
- include_examples 'requires block'
166
- include_examples 'Functor#fmap block evaluation'
167
- end
168
-
169
- describe '#apply' do
170
- def apply
171
- subject.apply(&block)
172
- end
173
-
174
- include_examples 'requires block'
175
- include_examples '#apply block evaluation'
176
- end
177
-
178
- describe '#from_left' do
179
- def apply
180
- subject.from_left(&block)
181
- end
182
-
183
- context 'without block' do
184
- let(:block) { nil }
185
-
186
- it 'raises RuntimeError error' do
187
- expect { apply }.to raise_error(
188
- RuntimeError,
189
- "Expected left value, got #{subject.inspect}"
190
- )
191
- end
192
- end
193
-
194
- context 'with block' do
195
- let(:yields) { [] }
196
- let(:block_return) { instance_double(Object, 'block-return') }
197
-
198
- let(:block) do
199
- lambda do |value|
200
- yields << value
201
- block_return
202
- end
203
- end
204
-
205
- it 'calls block with right value' do
206
- expect { apply }.to change(yields, :to_a).from([]).to([value])
207
- end
208
-
209
- it 'returns block value' do
210
- expect(apply).to be(block_return)
211
- end
212
- end
213
- end
214
-
215
- describe '#from_right' do
216
- def apply
217
- subject.from_right(&block)
218
- end
219
-
220
- it 'returns right value' do
221
- expect(apply).to be(value)
222
- end
223
-
224
- include_examples 'no block evaluation'
225
- end
226
-
227
- describe '#lmap' do
228
- def apply
229
- subject.lmap(&block)
230
- end
231
-
232
- include_examples 'requires block'
233
- include_examples 'no block evaluation'
234
-
235
- it 'returns self' do
236
- expect(apply).to be(subject)
237
- end
238
- end
239
-
240
- describe '#either' do
241
- def apply
242
- subject.either(-> { fail }, block)
243
- end
244
-
245
- include_examples '#apply block evaluation'
246
- end
247
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe Mutant::Maybe::Nothing do
4
- subject { described_class.new }
5
-
6
- let(:block) { -> {} }
7
-
8
- describe '#fmap' do
9
- def apply
10
- subject.fmap(&block)
11
- end
12
-
13
- include_examples 'no block evaluation'
14
- include_examples 'requires block'
15
- include_examples 'returns self'
16
- end
17
-
18
- describe '#apply' do
19
- def apply
20
- subject.apply(&block)
21
- end
22
-
23
- include_examples 'no block evaluation'
24
- include_examples 'requires block'
25
- include_examples 'returns self'
26
- end
27
- end
28
-
29
- RSpec.describe Mutant::Maybe::Just do
30
- subject { described_class.new(value) }
31
-
32
- let(:block_result) { instance_double(Object, 'block result') }
33
- let(:value) { instance_double(Object, 'value') }
34
- let(:yields) { [] }
35
-
36
- let(:block) do
37
- lambda do |value|
38
- yields << value
39
- block_result
40
- end
41
- end
42
-
43
- describe '#fmap' do
44
- def apply
45
- subject.fmap(&block)
46
- end
47
-
48
- include_examples 'requires block'
49
- include_examples 'Functor#fmap block evaluation'
50
- end
51
-
52
- describe '#apply' do
53
- def apply
54
- subject.apply(&block)
55
- end
56
-
57
- include_examples 'requires block'
58
- include_examples '#apply block evaluation'
59
- end
60
- end
@@ -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