plumbum 0.1.0

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.
@@ -0,0 +1,848 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rspec/sleeping_king_studios/deferred/provider'
4
+
5
+ require 'plumbum/rspec/deferred'
6
+
7
+ module Plumbum::RSpec::Deferred
8
+ # Deferred examples for validating Plumbum::Provider implementations.
9
+ module ProviderExamples
10
+ include RSpec::SleepingKingStudios::Deferred::Provider
11
+
12
+ # Asserts that the method handles invalid keys.
13
+ #
14
+ # The following methods must be defined in the example group:
15
+ #
16
+ # - #call_method: a helper method that takes one :key argument and calls the
17
+ # tested method.
18
+ deferred_examples 'should validate the key' do
19
+ include RSpec::SleepingKingStudios::Deferred::Dependencies
20
+
21
+ depends_on :call_method,
22
+ 'a helper method that takes one :key argument and calls the method ' \
23
+ 'under test'
24
+
25
+ define_method :tools do
26
+ SleepingKingStudios::Tools::Toolbelt.instance
27
+ end
28
+
29
+ describe 'with nil' do
30
+ let(:error_message) do
31
+ tools
32
+ .assertions
33
+ .error_message_for(
34
+ 'sleeping_king_studios.tools.assertions.presence',
35
+ as: :key
36
+ )
37
+ end
38
+
39
+ it 'should raise an exception' do
40
+ expect { call_method(nil) }
41
+ .to raise_error ArgumentError, error_message
42
+ end
43
+ end
44
+
45
+ describe 'with an Object' do
46
+ let(:error_message) do
47
+ tools
48
+ .assertions
49
+ .error_message_for(
50
+ 'sleeping_king_studios.tools.assertions.name',
51
+ as: :key
52
+ )
53
+ end
54
+
55
+ it 'should raise an exception' do
56
+ expect { call_method(Object.new.freeze) }
57
+ .to raise_error ArgumentError, error_message
58
+ end
59
+ end
60
+
61
+ describe 'with an empty String' do
62
+ let(:error_message) do
63
+ tools
64
+ .assertions
65
+ .error_message_for(
66
+ 'sleeping_king_studios.tools.assertions.presence',
67
+ as: :key
68
+ )
69
+ end
70
+
71
+ it 'should raise an exception' do
72
+ expect { call_method('') }
73
+ .to raise_error ArgumentError, error_message
74
+ end
75
+ end
76
+
77
+ describe 'with an empty Symbol' do
78
+ let(:error_message) do
79
+ tools
80
+ .assertions
81
+ .error_message_for(
82
+ 'sleeping_king_studios.tools.assertions.presence',
83
+ as: :key
84
+ )
85
+ end
86
+
87
+ it 'should raise an exception' do
88
+ expect { call_method(:'') }
89
+ .to raise_error ArgumentError, error_message
90
+ end
91
+ end
92
+ end
93
+
94
+ # Asserts that the provider handles incompatible options.
95
+ #
96
+ # The following methods must be defined in the example group:
97
+ #
98
+ # - #call_method: a helper method that takes one :options argument and calls
99
+ # the tested method.
100
+ deferred_examples 'should validate the options' do
101
+ include RSpec::SleepingKingStudios::Deferred::Dependencies
102
+
103
+ depends_on :call_method,
104
+ 'a helper method that takes one :options argument and calls the ' \
105
+ 'method under test'
106
+
107
+ describe 'with read_only: value and write_once: value' do
108
+ let(:options) do
109
+ super().merge(read_only: false, write_once: true)
110
+ end
111
+ let(:error_message) do
112
+ 'incompatible options :read_only and :write_once'
113
+ end
114
+
115
+ it 'should raise an exception' do
116
+ expect { call_method(options) }
117
+ .to raise_error ArgumentError, error_message
118
+ end
119
+ end
120
+ end
121
+
122
+ # Asserts that the object implements the Plumbum::Provider interface.
123
+ #
124
+ # The following methods must be defined in the example group:
125
+ #
126
+ # - #valid_pairs: A Hash containing the valid keys the provider should
127
+ # return and the corresponding values.
128
+ #
129
+ # The behavior can be customized by defining the following methods:
130
+ #
131
+ # - #invalid_key: An example key that does not match the provider. The
132
+ # default value is :invalid.
133
+ deferred_examples 'should implement the Provider interface' \
134
+ do |has_options: true|
135
+ include RSpec::SleepingKingStudios::Deferred::Dependencies
136
+
137
+ depends_on :valid_pairs,
138
+ 'a Hash containing the valid keys the provider should return and ' \
139
+ 'the corresponding values.'
140
+
141
+ describe '#get' do
142
+ let(:invalid_key) { defined?(super()) ? super() : :invalid }
143
+
144
+ define_method :call_method do |key|
145
+ subject.get(key)
146
+ end
147
+
148
+ it { expect(subject).to respond_to(:get).with(1).argument }
149
+
150
+ include_deferred 'should validate the key'
151
+
152
+ describe 'with an invalid String' do
153
+ it { expect(subject.get(invalid_key.to_s)).to be nil }
154
+ end
155
+
156
+ describe 'with an invalid Symbol' do
157
+ it { expect(subject.get(invalid_key.to_sym)).to be nil }
158
+ end
159
+
160
+ describe 'with a valid String', :aggregate_failures do
161
+ it 'should return the value' do
162
+ valid_pairs.each do |key, value|
163
+ expect(subject.get(key.to_s)).to be value
164
+ end
165
+ end
166
+ end
167
+
168
+ describe 'with a valid Symbol', :aggregate_failures do
169
+ it 'should return the value' do
170
+ valid_pairs.each do |key, value|
171
+ expect(subject.get(key.to_sym)).to be value
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ describe '#has?' do
178
+ let(:invalid_key) { defined?(super()) ? super() : :invalid }
179
+
180
+ define_method :call_method do |key|
181
+ subject.has?(key)
182
+ end
183
+
184
+ it 'should define the method' do
185
+ expect(subject)
186
+ .to respond_to(:has?)
187
+ .with(1).argument
188
+ .and_keywords(:allow_undefined)
189
+ end
190
+
191
+ include_deferred 'should validate the key'
192
+
193
+ describe 'with an invalid String' do
194
+ it { expect(subject.has?(invalid_key.to_s)).to be false }
195
+ end
196
+
197
+ describe 'with an invalid Symbol' do
198
+ it { expect(subject.has?(invalid_key.to_sym)).to be false }
199
+ end
200
+
201
+ describe 'with a valid String', :aggregate_failures do
202
+ it 'should return true' do
203
+ valid_pairs.each_key do |key|
204
+ expect(subject.has?(key.to_s)).to be true
205
+ end
206
+ end
207
+ end
208
+
209
+ describe 'with a valid Symbol', :aggregate_failures do
210
+ it 'should return true' do
211
+ valid_pairs.each_key do |key|
212
+ expect(subject.has?(key.to_sym)).to be true
213
+ end
214
+ end
215
+ end
216
+ end
217
+
218
+ describe '#options' do
219
+ include_examples 'should define reader', :options, -> { be_a Hash }
220
+
221
+ next unless has_options
222
+
223
+ it { expect(provider.options).to be == options }
224
+
225
+ context 'when initialized with options' do
226
+ let(:options) { super().merge(custom_option: 'custom value') }
227
+
228
+ it { expect(provider.options).to be == options }
229
+ end
230
+
231
+ context 'when initialized with read_only: false' do
232
+ let(:options) { super().merge(read_only: false) }
233
+
234
+ it { expect(provider.options).to be == options }
235
+ end
236
+
237
+ context 'when initialized with read_only: true' do
238
+ let(:options) { super().merge(read_only: true) }
239
+
240
+ it { expect(provider.options).to be == options }
241
+ end
242
+
243
+ context 'when initialized with write_once: false' do
244
+ let(:options) { super().merge(write_once: false) }
245
+
246
+ it { expect(provider.options).to be == options }
247
+ end
248
+
249
+ context 'when initialized with write_once: true' do
250
+ let(:options) { super().merge(write_once: true) }
251
+
252
+ it { expect(provider.options).to be == options }
253
+ end
254
+ end
255
+
256
+ describe '#read_only?' do
257
+ include_examples 'should define predicate', :read_only?
258
+
259
+ next unless has_options
260
+
261
+ it { expect(provider.read_only?).to be true }
262
+
263
+ context 'when initialized with read_only: false' do
264
+ let(:options) { super().merge(read_only: false) }
265
+
266
+ it { expect(provider.read_only?).to be false }
267
+ end
268
+
269
+ context 'when initialized with read_only: true' do
270
+ let(:options) { super().merge(read_only: true) }
271
+
272
+ it { expect(provider.read_only?).to be true }
273
+ end
274
+ end
275
+
276
+ describe '#set' do
277
+ let(:invalid_key) { defined?(super()) ? super() : :invalid }
278
+
279
+ define_method :call_method do |key|
280
+ subject.set(key, Object.new.freeze)
281
+ end
282
+
283
+ it { expect(subject).to respond_to(:set).with(2).arguments }
284
+
285
+ include_deferred 'should validate the key'
286
+ end
287
+
288
+ describe '#write_once?' do
289
+ include_examples 'should define predicate', :write_once?
290
+
291
+ next unless has_options
292
+
293
+ it { expect(provider.write_once?).to be false }
294
+
295
+ context 'when initialized with write_once: false' do
296
+ let(:options) { super().merge(write_once: false) }
297
+
298
+ it { expect(provider.write_once?).to be false }
299
+ end
300
+
301
+ context 'when initialized with write_once: true' do
302
+ let(:options) { super().merge(write_once: true) }
303
+
304
+ it { expect(provider.write_once?).to be true }
305
+ end
306
+ end
307
+ end
308
+
309
+ # Asserts that the object implements the interface for a plural Provider.
310
+ #
311
+ # The following methods must be defined in the example group:
312
+ #
313
+ # - #valid_keys: The valid keys configured for the provider.
314
+ #
315
+ # The behavior can be customized by defining the following methods:
316
+ #
317
+ # - #invalid_key: An example key that does not match the provider. The
318
+ # default value is :invalid.
319
+ # - #mutable_keys: The keys with mutable values. Defaults to the value of
320
+ # #valid_keys.
321
+ deferred_examples 'should implement the plural Provider interface' \
322
+ do |has_options: true, mutable_values: false|
323
+ include RSpec::SleepingKingStudios::Deferred::Dependencies
324
+
325
+ depends_on :valid_keys, 'the valid keys configured for the provider'
326
+
327
+ describe '#set' do
328
+ let(:invalid_key) { defined?(super()) ? super() : :invalid }
329
+ let(:changed_value) { Object.new.freeze }
330
+
331
+ describe 'with an invalid String', :aggregate_failures do
332
+ let(:error_message) do
333
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
334
+ end
335
+
336
+ it 'should raise an exception' do
337
+ expect { provider.set(invalid_key.to_s, changed_value) }
338
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
339
+ end
340
+ end
341
+
342
+ describe 'with an invalid Symbol', :aggregate_failures do
343
+ let(:error_message) do
344
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
345
+ end
346
+
347
+ it 'should raise an exception' do
348
+ expect { provider.set(invalid_key.to_sym, changed_value) }
349
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
350
+ end
351
+ end
352
+
353
+ describe 'with an valid String', :aggregate_failures do
354
+ let(:error_message) do
355
+ "unable to change immutable value for #{provider.class} with key " \
356
+ "#{valid_keys.first.to_s.inspect}"
357
+ end
358
+
359
+ it 'should raise an exception' do
360
+ next if valid_keys.empty?
361
+
362
+ expect { provider.set(valid_keys.first.to_s, changed_value) }
363
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
364
+ end
365
+ end
366
+
367
+ describe 'with an valid Symbol', :aggregate_failures do
368
+ let(:error_message) do
369
+ "unable to change immutable value for #{provider.class} with key " \
370
+ "#{valid_keys.first.to_s.inspect}"
371
+ end
372
+
373
+ it 'should raise an exception' do
374
+ next if valid_keys.empty?
375
+
376
+ expect { provider.set(valid_keys.first.to_sym, changed_value) }
377
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
378
+ end
379
+ end
380
+
381
+ if mutable_values
382
+ describe 'with a String for an mutable key' do
383
+ let(:mutable_key) { mutable_keys.first }
384
+ let(:error_message) do
385
+ "unable to change immutable value for #{provider.class} with " \
386
+ "key #{mutable_key.to_s.inspect}"
387
+ end
388
+
389
+ it 'should raise an exception' do
390
+ expect { provider.set(mutable_key.to_s, changed_value) }
391
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
392
+ end
393
+ end
394
+
395
+ describe 'with a Symbol for an mutable key' do
396
+ let(:mutable_key) { mutable_keys.first }
397
+ let(:error_message) do
398
+ "unable to change immutable value for #{provider.class} with " \
399
+ "key #{mutable_key.to_s.inspect}"
400
+ end
401
+
402
+ it 'should raise an exception' do
403
+ expect { provider.set(mutable_key.to_sym, changed_value) }
404
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
405
+ end
406
+ end
407
+ end
408
+
409
+ next unless has_options
410
+
411
+ context 'when initialized with read_only: false' do
412
+ let(:options) { super().merge(read_only: false) }
413
+
414
+ describe 'with an invalid String', :aggregate_failures do
415
+ let(:error_message) do
416
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
417
+ end
418
+
419
+ it 'should raise an exception' do
420
+ expect { provider.set(invalid_key.to_s, changed_value) }
421
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
422
+ end
423
+ end
424
+
425
+ describe 'with an invalid Symbol', :aggregate_failures do
426
+ let(:error_message) do
427
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
428
+ end
429
+
430
+ it 'should raise an exception' do
431
+ expect { provider.set(invalid_key.to_sym, changed_value) }
432
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
433
+ end
434
+ end
435
+
436
+ describe 'with an valid String', :aggregate_failures do
437
+ it 'should update the value' do
438
+ valid_keys.each do |valid_key|
439
+ expect { provider.set(valid_key.to_s, changed_value) }.to(
440
+ change { provider.get(valid_key) }.to(be == changed_value)
441
+ )
442
+ end
443
+ end
444
+ end
445
+
446
+ describe 'with an valid Symbol', :aggregate_failures do
447
+ it 'should update the value' do
448
+ valid_keys.each do |valid_key|
449
+ expect { provider.set(valid_key.to_sym, changed_value) }.to(
450
+ change { provider.get(valid_key) }.to(be == changed_value)
451
+ )
452
+ end
453
+ end
454
+ end
455
+
456
+ if mutable_values
457
+ describe 'with a String for an mutable key' do
458
+ let(:mutable_key) { mutable_keys.first }
459
+
460
+ it 'should update the value' do
461
+ expect { provider.set(mutable_key.to_s, changed_value) }.to(
462
+ change { provider.get(mutable_key) }.to(be == changed_value)
463
+ )
464
+ end
465
+ end
466
+
467
+ describe 'with a Symbol for an mutable key' do
468
+ let(:mutable_key) { mutable_keys.first }
469
+
470
+ it 'should update the value' do
471
+ expect { provider.set(mutable_key.to_sym, changed_value) }.to(
472
+ change { provider.get(mutable_key) }.to(be == changed_value)
473
+ )
474
+ end
475
+ end
476
+ end
477
+
478
+ context 'when the provider is frozen' do
479
+ let(:error_message) do
480
+ "can't modify frozen #{described_class}: #{provider.inspect}"
481
+ end
482
+
483
+ before(:example) { provider.freeze }
484
+
485
+ describe 'with an invalid String', :aggregate_failures do
486
+ it 'should raise an exception' do
487
+ expect { provider.set(invalid_key.to_s, changed_value) }
488
+ .to raise_error FrozenError, error_message
489
+ end
490
+ end
491
+
492
+ describe 'with an invalid Symbol', :aggregate_failures do
493
+ it 'should raise an exception' do
494
+ expect { provider.set(invalid_key.to_sym, changed_value) }
495
+ .to raise_error FrozenError, error_message
496
+ end
497
+ end
498
+
499
+ describe 'with an valid String', :aggregate_failures do
500
+ it 'should raise an exception' do
501
+ valid_keys.each do |valid_key|
502
+ expect { provider.set(valid_key.to_s, changed_value) }
503
+ .to raise_error FrozenError, error_message
504
+ end
505
+ end
506
+ end
507
+
508
+ describe 'with an valid Symbol', :aggregate_failures do
509
+ it 'should raise an exception' do
510
+ valid_keys.each do |valid_key|
511
+ expect { provider.set(valid_key.to_sym, changed_value) }
512
+ .to raise_error FrozenError, error_message
513
+ end
514
+ end
515
+ end
516
+ end
517
+ end
518
+
519
+ context 'when initialized with write_once: true' do
520
+ let(:options) { super().merge(write_once: true) }
521
+ let(:mutable_keys) { defined?(super()) ? super() : [] }
522
+ let(:mutable_key) { mutable_keys.first }
523
+ let(:immutable_key) { (valid_keys - mutable_keys).first }
524
+
525
+ describe 'with an invalid String', :aggregate_failures do
526
+ let(:error_message) do
527
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
528
+ end
529
+
530
+ it 'should raise an exception' do
531
+ expect { provider.set(invalid_key.to_s, changed_value) }
532
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
533
+ end
534
+ end
535
+
536
+ describe 'with an invalid Symbol', :aggregate_failures do
537
+ let(:error_message) do
538
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
539
+ end
540
+
541
+ it 'should raise an exception' do
542
+ expect { provider.set(invalid_key.to_sym, changed_value) }
543
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
544
+ end
545
+ end
546
+
547
+ describe 'with a String for an immutable key' do
548
+ let(:error_message) do
549
+ "unable to change immutable value for #{provider.class} with " \
550
+ "key #{valid_keys.first.to_s.inspect}"
551
+ end
552
+
553
+ it 'should raise an exception' do
554
+ next if valid_keys.empty?
555
+
556
+ expect { provider.set(immutable_key.to_s, changed_value) }
557
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
558
+ end
559
+ end
560
+
561
+ describe 'with a Symbol for an immutable key' do
562
+ let(:error_message) do
563
+ "unable to change immutable value for #{provider.class} with " \
564
+ "key #{valid_keys.first.to_s.inspect}"
565
+ end
566
+
567
+ it 'should raise an exception' do
568
+ next if valid_keys.empty?
569
+
570
+ expect { provider.set(immutable_key.to_sym, changed_value) }
571
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
572
+ end
573
+ end
574
+
575
+ next unless mutable_values
576
+
577
+ describe 'with a String for an mutable key' do
578
+ it 'should update the value' do
579
+ expect { provider.set(mutable_key.to_s, changed_value) }.to(
580
+ change { provider.get(mutable_key) }.to(be == changed_value)
581
+ )
582
+ end
583
+ end
584
+
585
+ describe 'with a Symbol for an mutable key' do
586
+ it 'should update the value' do
587
+ expect { provider.set(mutable_key.to_sym, changed_value) }.to(
588
+ change { provider.get(mutable_key) }.to(be == changed_value)
589
+ )
590
+ end
591
+ end
592
+ end
593
+ end
594
+ end
595
+
596
+ # Asserts that the object implements the interface for a singular Provider.
597
+ #
598
+ # The following methods must be defined in the example group:
599
+ #
600
+ # - #valid_key: The valid key configured for the provider.
601
+ #
602
+ # The behavior can be customized by defining the following methods:
603
+ #
604
+ # - #invalid_key: An example key that does not match the provider. The
605
+ # default value is :invalid.
606
+ deferred_examples 'should implement the singular Provider interface' \
607
+ do |has_options: true, mutable_value: false|
608
+ include RSpec::SleepingKingStudios::Deferred::Dependencies
609
+
610
+ depends_on :valid_key, 'the valid key configured for the provider'
611
+
612
+ describe '#set' do
613
+ let(:invalid_key) { defined?(super()) ? super() : :invalid }
614
+ let(:changed_value) { Object.new.freeze }
615
+
616
+ describe 'with an invalid String', :aggregate_failures do
617
+ let(:error_message) do
618
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
619
+ end
620
+
621
+ it 'should raise an exception' do
622
+ expect { provider.set(invalid_key.to_s, changed_value) }
623
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
624
+ end
625
+ end
626
+
627
+ describe 'with an invalid Symbol', :aggregate_failures do
628
+ let(:error_message) do
629
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
630
+ end
631
+
632
+ it 'should raise an exception' do
633
+ expect { provider.set(invalid_key.to_sym, changed_value) }
634
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
635
+ end
636
+ end
637
+
638
+ describe 'with an valid String', :aggregate_failures do
639
+ let(:error_message) do
640
+ "unable to change immutable value for #{provider.class} with key " \
641
+ "#{valid_key.to_s.inspect}"
642
+ end
643
+
644
+ it 'should raise an exception' do
645
+ expect { provider.set(valid_key.to_s, changed_value) }
646
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
647
+ end
648
+ end
649
+
650
+ describe 'with a valid Symbol', :aggregate_failures do
651
+ let(:error_message) do
652
+ "unable to change immutable value for #{provider.class} with key " \
653
+ "#{valid_key.to_s.inspect}"
654
+ end
655
+
656
+ it 'should raise an exception' do
657
+ expect { provider.set(valid_key.to_sym, changed_value) }
658
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
659
+ end
660
+ end
661
+
662
+ next unless has_options
663
+
664
+ context 'when initialized with read_only: false' do
665
+ let(:options) { super().merge(read_only: false) }
666
+
667
+ describe 'with an invalid String', :aggregate_failures do
668
+ let(:error_message) do
669
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
670
+ end
671
+
672
+ it 'should raise an exception' do
673
+ expect { provider.set(invalid_key.to_s, changed_value) }
674
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
675
+ end
676
+ end
677
+
678
+ describe 'with an invalid Symbol', :aggregate_failures do
679
+ let(:error_message) do
680
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
681
+ end
682
+
683
+ it 'should raise an exception' do
684
+ expect { provider.set(invalid_key.to_sym, changed_value) }
685
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
686
+ end
687
+ end
688
+
689
+ describe 'with an valid String', :aggregate_failures do
690
+ it 'should update the value' do
691
+ expect { provider.set(valid_key.to_s, changed_value) }.to(
692
+ change { provider.get(valid_key) }.to(be == changed_value)
693
+ )
694
+ end
695
+ end
696
+
697
+ describe 'with an valid Symbol', :aggregate_failures do
698
+ it 'should update the value' do
699
+ expect { provider.set(valid_key.to_sym, changed_value) }.to(
700
+ change { provider.get(valid_key) }.to(be == changed_value)
701
+ )
702
+ end
703
+ end
704
+
705
+ context 'when the provider is frozen' do
706
+ let(:error_message) do
707
+ "can't modify frozen #{described_class}: #{provider.inspect}"
708
+ end
709
+
710
+ before(:example) { provider.freeze }
711
+
712
+ describe 'with an invalid String', :aggregate_failures do
713
+ it 'should raise an exception' do
714
+ expect { provider.set(invalid_key.to_s, changed_value) }
715
+ .to raise_error FrozenError, error_message
716
+ end
717
+ end
718
+
719
+ describe 'with an invalid Symbol', :aggregate_failures do
720
+ it 'should raise an exception' do
721
+ expect { provider.set(invalid_key.to_sym, changed_value) }
722
+ .to raise_error FrozenError, error_message
723
+ end
724
+ end
725
+
726
+ describe 'with a valid String', :aggregate_failures do
727
+ it 'should raise an exception' do
728
+ expect { provider.set(valid_key.to_s, changed_value) }
729
+ .to raise_error FrozenError, error_message
730
+ end
731
+ end
732
+
733
+ describe 'with a valid Symbol', :aggregate_failures do
734
+ it 'should raise an exception' do
735
+ expect { provider.set(valid_key.to_sym, changed_value) }
736
+ .to raise_error FrozenError, error_message
737
+ end
738
+ end
739
+ end
740
+ end
741
+
742
+ context 'when initialized with write_once: true' do
743
+ let(:options) { super().merge(write_once: true) }
744
+
745
+ describe 'with an invalid String', :aggregate_failures do
746
+ let(:error_message) do
747
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
748
+ end
749
+
750
+ it 'should raise an exception' do
751
+ expect { provider.set(invalid_key.to_s, changed_value) }
752
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
753
+ end
754
+ end
755
+
756
+ describe 'with an invalid Symbol', :aggregate_failures do
757
+ let(:error_message) do
758
+ "invalid key #{invalid_key.to_s.inspect} for #{provider.class}"
759
+ end
760
+
761
+ it 'should raise an exception' do
762
+ expect { provider.set(invalid_key.to_sym, changed_value) }
763
+ .to raise_error Plumbum::Errors::InvalidKeyError, error_message
764
+ end
765
+ end
766
+
767
+ if mutable_value
768
+ describe 'with an valid String', :aggregate_failures do
769
+ it 'should update the value' do
770
+ expect { provider.set(valid_key.to_s, changed_value) }.to(
771
+ change { provider.get(valid_key) }.to(be == changed_value)
772
+ )
773
+ end
774
+ end
775
+
776
+ describe 'with an valid Symbol', :aggregate_failures do
777
+ it 'should update the value' do
778
+ expect { provider.set(valid_key.to_sym, changed_value) }.to(
779
+ change { provider.get(valid_key) }.to(be == changed_value)
780
+ )
781
+ end
782
+ end
783
+ else
784
+ describe 'with an valid String', :aggregate_failures do
785
+ let(:error_message) do
786
+ "unable to change immutable value for #{provider.class} " \
787
+ "with key #{valid_key.to_s.inspect}"
788
+ end
789
+
790
+ it 'should raise an exception' do
791
+ expect { provider.set(valid_key.to_s, changed_value) }
792
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
793
+ end
794
+ end
795
+
796
+ describe 'with a valid Symbol', :aggregate_failures do
797
+ let(:error_message) do
798
+ "unable to change immutable value for #{provider.class} " \
799
+ "with key #{valid_key.to_s.inspect}"
800
+ end
801
+
802
+ it 'should raise an exception' do
803
+ expect { provider.set(valid_key.to_sym, changed_value) }
804
+ .to raise_error Plumbum::Errors::ImmutableError, error_message
805
+ end
806
+ end
807
+ end
808
+
809
+ context 'when the provider is frozen' do
810
+ let(:error_message) do
811
+ "can't modify frozen #{described_class}: #{provider.inspect}"
812
+ end
813
+
814
+ before(:example) { provider.freeze }
815
+
816
+ describe 'with an invalid String', :aggregate_failures do
817
+ it 'should raise an exception' do
818
+ expect { provider.set(invalid_key.to_s, changed_value) }
819
+ .to raise_error FrozenError, error_message
820
+ end
821
+ end
822
+
823
+ describe 'with an invalid Symbol', :aggregate_failures do
824
+ it 'should raise an exception' do
825
+ expect { provider.set(invalid_key.to_sym, changed_value) }
826
+ .to raise_error FrozenError, error_message
827
+ end
828
+ end
829
+
830
+ describe 'with a valid String', :aggregate_failures do
831
+ it 'should raise an exception' do
832
+ expect { provider.set(valid_key.to_s, changed_value) }
833
+ .to raise_error FrozenError, error_message
834
+ end
835
+ end
836
+
837
+ describe 'with a valid Symbol', :aggregate_failures do
838
+ it 'should raise an exception' do
839
+ expect { provider.set(valid_key.to_sym, changed_value) }
840
+ .to raise_error FrozenError, error_message
841
+ end
842
+ end
843
+ end
844
+ end
845
+ end
846
+ end
847
+ end
848
+ end