must_be 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,952 @@
1
+ require 'spec_helper'
2
+
3
+ describe MustBe do
4
+ include MustBeExampleHelper
5
+
6
+ describe ContainerNote do
7
+ describe '#to_s' do
8
+ context "when original_note has no assertion" do
9
+ it "should just use original_note's message" do
10
+ note = ContainerNote.new(Note.new("message"))
11
+ note.to_s.should == Note.new("message").to_s
12
+ end
13
+ end
14
+ end
15
+
16
+ describe '#backtrace' do
17
+ context "when #must_only_ever_contain has been called" do
18
+ subject do
19
+ note = ContainerNote.new(Note.new("nothing"),
20
+ [].must_only_ever_contain)
21
+ note.set_backtrace([])
22
+ note
23
+ end
24
+
25
+ its(:backtrace) { should include("=== caused by container ===")}
26
+ end
27
+
28
+ context "when #must_only_ever_contain has not been called" do
29
+ subject do
30
+ note = ContainerNote.new(Note.new("nothing"), [])
31
+ note.set_backtrace([])
32
+ note
33
+ end
34
+
35
+ its(:backtrace) { should_not include("=== caused by container ===")}
36
+ end
37
+ end
38
+ end
39
+
40
+ describe '#must_only_contain' do
41
+ context "when called on an array" do
42
+ subject { [11, :sin, 'cos'] }
43
+
44
+ it "should not notify if every member matches one of the cases" do
45
+ subject.must_only_contain(Symbol, Numeric, String).should == subject
46
+ should_not notify
47
+ end
48
+
49
+ it "should notify if any member matches none of the cases" do
50
+ subject.must_only_contain(Symbol, Numeric).should == subject
51
+ should notify("must_only_contain: \"cos\".must_be(Symbol, Numeric),"\
52
+ " but matches String in container [11, :sin, \"cos\"]")
53
+ end
54
+
55
+ context "when there are no cases" do
56
+ it "should notify if any member is false or nil" do
57
+ [false, nil].must_only_contain
58
+ should notify
59
+ end
60
+
61
+ it "should not notify if every member is neither false nor nil" do
62
+ [0, [], ""].must_only_contain
63
+ should_not notify
64
+ end
65
+ end
66
+ end
67
+
68
+ describe "when called on a hash" do
69
+ subject { {:key => :value, :another => 'thing', 12 => 43} }
70
+
71
+ describe "note message" do
72
+ it "should include \"does not match\"" do
73
+ subject = {:key => :value}
74
+ subject.must_only_contain(Symbol => [String, Numeric])
75
+ should notify("must_only_contain: pair {:key=>:value} does"\
76
+ " not match [{Symbol=>[String, Numeric]}] in container"\
77
+ " {:key=>:value}")
78
+ end
79
+ end
80
+
81
+ context "when called with no arguments" do
82
+ it "should not notifiy if every key and value is non-nil" do
83
+ subject = {:key => :value}
84
+ subject.must_only_contain
85
+ should_not notify
86
+ end
87
+
88
+ it "should notify if any pair contains a nil key" do
89
+ subject = {nil => :value}
90
+ subject.must_only_contain
91
+ should notify
92
+ end
93
+
94
+ it "should notify if any pair contains a nil value" do
95
+ subject = {:key => nil}
96
+ subject.must_only_contain
97
+ should notify
98
+ end
99
+ end
100
+
101
+ context "when called with a single hash" do
102
+ it "should not notify if every pair matches one of the cases" do
103
+ subject.must_only_contain(Symbol => [Symbol, String],
104
+ Numeric => Numeric).should == subject
105
+ should_not notify
106
+ end
107
+
108
+ it "should notify if any pair matches none of the cases" do
109
+ subject.must_only_contain(Symbol => Symbol, Symbol => String,
110
+ String => Numeric).should == subject
111
+ should notify
112
+ end
113
+ end
114
+
115
+ context "when called with multiple hashes" do
116
+ it "should not notify if every pair matches one of the cases" do
117
+ subject.must_only_contain({Symbol => Symbol}, {Symbol => String},
118
+ {Numeric => Numeric}).should == subject
119
+ should_not notify
120
+ end
121
+
122
+ it "should notify if any pair matches none of the cases" do
123
+ subject.must_only_contain({Symbol => Symbol}, {Symbol => String},
124
+ {String => Numeric}).should == subject
125
+ should notify
126
+ end
127
+ end
128
+
129
+ context "when called with array keys and values" do
130
+ it "should not notify if every pair matches one of the cases" do
131
+ subject.must_only_contain([Symbol, Numeric] => [Symbol, String,
132
+ Numeric]).should == subject
133
+ should_not notify
134
+ end
135
+
136
+ it "should notify if any pair does not match any of the cases" do
137
+ subject.must_only_contain([Symbol, Numeric] => [Symbol,
138
+ Numeric]).should == subject
139
+ should notify
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ describe '#must_not_contain' do
146
+ context "when called on an array" do
147
+ subject { [11, :sin, 'cos'] }
148
+
149
+ it "should not notify if no member matches any of the cases" do
150
+ subject.must_not_contain(Float, Range).should == subject
151
+ should_not notify
152
+ end
153
+
154
+ it "should notify if any member matches one of the cases" do
155
+ subject.must_not_contain(Range, Numeric).should == subject
156
+ should notify("must_not_contain: 11.must_not_be(Range, Numeric),"\
157
+ " but matches Fixnum in container [11, :sin, \"cos\"]")
158
+ end
159
+
160
+ context "when there are no cases" do
161
+ it "should not notify if every member is false or nil" do
162
+ [false, nil].must_not_contain
163
+ should_not notify
164
+ end
165
+
166
+ it "should notify if any member is neither false nor nil" do
167
+ [0, [], ""].must_not_contain
168
+ should notify
169
+ end
170
+ end
171
+ end
172
+
173
+ context "when called on a hash" do
174
+ subject { {:key => :value, :another => 'thing', 12 => 43} }
175
+
176
+ context "when called with no arguments" do
177
+ it "should not notifiy if every key and value"\
178
+ " is false or nil" do
179
+ subject = {nil => false, false => nil}
180
+ subject.must_not_contain
181
+ should_not notify
182
+ end
183
+
184
+ it "should notify if any key or value is conitionally true" do
185
+ subject = {nil => :value}
186
+ subject.must_not_contain
187
+ should notify
188
+ end
189
+ end
190
+
191
+ describe "note message" do
192
+ it "should include \"does match\"" do
193
+ subject = {:key => :value}
194
+ subject.must_not_contain(Symbol => [String, Symbol])
195
+ should notify("must_not_contain: pair {:key=>:value} matches"\
196
+ " [{Symbol=>[String, Symbol]}] in container {:key=>:value}")
197
+ end
198
+ end
199
+
200
+ context "when called with a single hash" do
201
+ it "should notify if any pair matches one of the cases" do
202
+ subject.must_not_contain(Symbol => [Symbol, String],
203
+ Numeric => Numeric).should == subject
204
+ should notify
205
+ end
206
+
207
+ it "should_not notify if no pair matches any of the cases" do
208
+ subject.must_not_contain(Symbol => Numeric, String => String,
209
+ Range => Numeric).should == subject
210
+ should_not notify
211
+ end
212
+ end
213
+
214
+ context "when called with multiple hashes" do
215
+ it "should not notify if no pair matches any of the cases" do
216
+ subject.must_not_contain({Symbol => Numeric}, {String => String},
217
+ {String => Numeric}).should == subject
218
+ should_not notify
219
+ end
220
+
221
+ it "should notify if any pair matches any of the cases" do
222
+ subject.must_not_contain({Symbol => Symbol}, {Symbol => String},
223
+ {String => Numeric}).should == subject
224
+ should notify
225
+ end
226
+ end
227
+
228
+ context "when called with array keys and values" do
229
+ it "should not notify if no pair matches any of the cases" do
230
+ subject.must_not_contain([Range, Numeric] => [Symbol, String,
231
+ Float]).should == subject
232
+ should_not notify
233
+ end
234
+
235
+ it "should notify if any pair matches one of the cases" do
236
+ subject.must_not_contain([Symbol, Numeric] => [Symbol,
237
+ Numeric]).should == subject
238
+ should notify
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ shared_examples_for "custom MustOnlyEverContain" do
245
+ class Box
246
+ include Enumerable
247
+
248
+ attr_accessor :contents
249
+
250
+ def initialize(contents = nil)
251
+ self.contents = contents
252
+ end
253
+
254
+ def each_called?
255
+ @each_called
256
+ end
257
+
258
+ def each
259
+ @each_called = true
260
+ yield(contents) unless contents.nil?
261
+ end
262
+
263
+ def empty!
264
+ self.contents = nil
265
+ end
266
+ end
267
+
268
+ subject { Box.new(:contents) }
269
+
270
+ def self.register_before_and_unregister_after
271
+ before do
272
+ MustOnlyEverContain.register(Box) do
273
+ def self.must_only_contain_check(object, cases, negate = false)
274
+ if negate
275
+ object.contents.must_not_be(*cases)
276
+ else
277
+ object.contents.must_be(*cases)
278
+ end
279
+ end
280
+
281
+ def contents=(contents)
282
+ must_check_member(contents)
283
+ super
284
+ end
285
+
286
+ must_check_contents_after :empty!
287
+ end
288
+ end
289
+
290
+ after do
291
+ MustOnlyEverContain.unregister(Box)
292
+ end
293
+ end
294
+ end
295
+
296
+ describe '#must_only_ever_contain' do
297
+ context "when called on an array" do
298
+ subject { [1, 2, 3, 4] }
299
+
300
+ before do
301
+ subject.must_only_ever_contain
302
+ end
303
+
304
+ it "should notify if initially contains a non-matching member" do
305
+ array = [:oops]
306
+ array.must_only_ever_contain(String)
307
+ should notify("must_only_ever_contain: :oops.must_be(String), but"\
308
+ " matches Symbol in container [:oops]")
309
+ end
310
+
311
+ context "after disabling" do
312
+ before do
313
+ @enabled_array = [].must_only_ever_contain(Fixnum)
314
+ end
315
+
316
+ before_disable_after_enable
317
+
318
+ context "when #must_only_ever_contain was called while still"\
319
+ " enabled" do
320
+ it "should not notify" do
321
+ @enabled_array << 3.2
322
+ should_not notify
323
+ end
324
+
325
+ it "should continue to have singleton methods" do
326
+ @enabled_array.singleton_methods.should_not be_empty
327
+ end
328
+
329
+ context "after being re-enabled" do
330
+ before do
331
+ MustBe.enable
332
+ end
333
+
334
+ it "should notify again" do
335
+ @enabled_array << 3.2
336
+ should notify(/must_only_ever_contain: Array#<<\(3.2\)/)
337
+ end
338
+ end
339
+ end
340
+
341
+ context "when #must_only_ever_contain is called" do
342
+ before do
343
+ @disabled_array = [].must_only_ever_contain(Fixnum)
344
+ end
345
+
346
+ it "should not notify" do
347
+ @disabled_array << 3.2
348
+ should_not notify
349
+ end
350
+
351
+ it "should not have singleton methods" do
352
+ @disabled_array.singleton_methods.should be_empty
353
+ end
354
+
355
+ context "after being re-enabled" do
356
+ before do
357
+ MustBe.enable
358
+ end
359
+
360
+ it "should still not notify" do
361
+ @disabled_array << 3.2
362
+ should_not notify
363
+ end
364
+ end
365
+ end
366
+ end
367
+
368
+ describe '#<<' do
369
+ it "should not notify if obj is non-nil" do
370
+ subject << 5
371
+ should_not notify
372
+ end
373
+
374
+ it "should notify if obj is nil" do
375
+ subject << nil
376
+ should notify("must_only_ever_contain: Array#<<(nil):"\
377
+ " nil.must_be, but matches NilClass in container"\
378
+ " [1, 2, 3, 4, nil]")
379
+ end
380
+ end
381
+
382
+ describe '#[]=' do
383
+ context "when called with index" do
384
+ it "should not notify if obj is non-nil" do
385
+ subject[2] = 5
386
+ should_not notify
387
+ end
388
+
389
+ it "should notify if obj is nil" do
390
+ subject[2] = nil
391
+ should notify
392
+ end
393
+ end
394
+
395
+ context "when called with start and length" do
396
+ it "should not notify if obj is non-nil" do
397
+ subject[2, 2] = 5
398
+ should_not notify
399
+ end
400
+
401
+ it "should not notify if obj is nil" do
402
+ subject[2, 2] = nil
403
+ should_not notify
404
+ end
405
+
406
+ it "should not notify if obj is compact array" do
407
+ subject[2, 2] = [8, 9, 0]
408
+ end
409
+
410
+ it "should notify if obj is array containing nil" do
411
+ subject[2, 2] = [8, nil, 0]
412
+ should notify("must_only_ever_contain:"\
413
+ " Array#[]=(2, 2, [8, nil, 0]): nil.must_be,"\
414
+ " but matches NilClass in"\
415
+ " container [1, 2, 8, nil, 0]")
416
+ end
417
+ end
418
+
419
+ context "when called with range" do
420
+ it "should not notify if obj is non-nil obj" do
421
+ subject[2..4] = 5
422
+ should_not notify
423
+ end
424
+
425
+ it "should not notify if obj is nil" do
426
+ subject[2..4] = nil
427
+ should_not notify
428
+ end
429
+
430
+ it "should not notify if obj is compact array" do
431
+ subject[2..4] = [8, 9, 0]
432
+ end
433
+
434
+ it "should notify if obj is array containing nil" do
435
+ subject[2..4] = [8, nil, 0]
436
+ should notify
437
+ end
438
+ end
439
+ end
440
+
441
+ describe '#collect!' do
442
+ it "should not notify if all new values are non-nil" do
443
+ subject.collect! {|v| v }
444
+ should_not notify
445
+ end
446
+
447
+ it "should notify if any new values are nil" do
448
+ subject.collect! {|v| v == 3 ? nil : v }
449
+ should notify
450
+ end
451
+ end
452
+
453
+ describe '#map!' do
454
+ it "should not notify if all new values are non-nil" do
455
+ subject.map! {|v| v }
456
+ should_not notify
457
+ end
458
+
459
+ it "should notify if any new values are nil" do
460
+ subject.map! {|v| v == 3 ? nil : v }
461
+ should notify("must_only_ever_contain: Array#map! {}:"\
462
+ " nil.must_be, but matches NilClass in container [1, 2, nil, 4]")
463
+ end
464
+ end
465
+
466
+ describe '#concat' do
467
+ it "should not notify if all members in other_array are non-nil" do
468
+ subject.concat([6, 7, 8, 9])
469
+ should_not notify
470
+ end
471
+
472
+ it "should notify if any member in other_array is nil" do
473
+ subject.concat([6, 7, nil, 9])
474
+ should notify
475
+ end
476
+ end
477
+
478
+ describe '#fill' do
479
+ context "when called without a block" do
480
+ it "should not notify if obj is non-nil" do
481
+ subject.fill(3)
482
+ should_not notify
483
+ end
484
+
485
+ it "should notify if obj is nil" do
486
+ subject.fill(nil)
487
+ should notify("must_only_ever_contain: Array#fill(nil):"\
488
+ " nil.must_be, but matches NilClass in container"\
489
+ " [nil, nil, nil, nil]")
490
+ end
491
+ end
492
+
493
+ context "when called with a block" do
494
+ it "should not notify if block never returns nil" do
495
+ subject.fill {|v| v }
496
+ should_not notify
497
+ end
498
+
499
+ it "should notify if block ever returns nil" do
500
+ subject.fill {|v| v == 3 ? nil : v }
501
+ should notify
502
+ end
503
+ end
504
+ end
505
+
506
+ describe '#flatten!' do
507
+ it "should not notify if does not contain an array with"\
508
+ " nil members" do
509
+ subject << [[6, 7], [8, 9]]
510
+ subject.flatten!
511
+ should_not notify
512
+ end
513
+
514
+ it "should notify if contains an array with any nil members" do
515
+ subject << [[6, 7], [nil, 9]]
516
+ subject.flatten!
517
+ should notify
518
+ end
519
+ end
520
+
521
+ describe '#insert' do
522
+ it "should not notify if all objs are non-nil" do
523
+ subject.insert(2, 6, 7, 8, 9)
524
+ should_not notify
525
+ end
526
+
527
+ it "should notify if any objs are nil" do
528
+ subject.insert(2, 6, 7, nil, 9)
529
+ should notify
530
+ end
531
+ end
532
+
533
+ describe '#push' do
534
+ it "should not notify if all objs are non-nil" do
535
+ subject.push(6, 7, 8, 9)
536
+ should_not notify
537
+ end
538
+
539
+ it "should notify if any objs are nil" do
540
+ subject.push(6, 7, nil, 9)
541
+ should notify("must_only_ever_contain: Array#push(6, 7, nil, 9):"\
542
+ " nil.must_be, but matches NilClass in container"\
543
+ " [6, 7, nil, 9]")
544
+ end
545
+ end
546
+
547
+ describe '#replace' do
548
+ it "should not notify if all members in other_array are non-nil" do
549
+ subject.replace([6, 7, 8, 9])
550
+ should_not notify
551
+ end
552
+
553
+ it "should notify if any members in other_array are nil" do
554
+ subject.replace([6, 7, nil, 9])
555
+ should notify
556
+ end
557
+ end
558
+
559
+ describe '#unshift' do
560
+ it "should not notify if all objs are non-nil" do
561
+ subject.unshift(6, 7, 8, 9)
562
+ should_not notify
563
+ end
564
+
565
+ it "should notify if any objs are nil" do
566
+ subject.unshift(6, 7, nil, 9)
567
+ should notify
568
+ end
569
+ end
570
+ end
571
+
572
+ context "when called on a hash" do
573
+ subject { {} }
574
+
575
+ context "when called with no arguments" do
576
+ before do
577
+ subject.must_only_ever_contain
578
+ end
579
+
580
+ example "must_only_ever_contain_cases should == []" do
581
+ subject.must_only_ever_contain_cases.should == []
582
+ end
583
+
584
+ it "should notify if inserting a nil value" do
585
+ subject[:nil] = nil
586
+ should notify
587
+ end
588
+
589
+ it "should notify if inserting a false key" do
590
+ subject[false] = :false
591
+ should notify("must_only_ever_contain: Hash#[]=(false, :false):"\
592
+ " pair {false=>:false} does not match [] in container"\
593
+ " {false=>:false}")
594
+ end
595
+
596
+ it "should not notify if inserting a regular pair" do
597
+ subject[:key] = :value
598
+ should_not notify
599
+ end
600
+ end
601
+
602
+ context "when called with a hash" do
603
+ before do
604
+ subject.must_only_ever_contain(Symbol => Integer, Integer => Symbol)
605
+ end
606
+
607
+ it "should notify if inserting a non-matching key" do
608
+ subject["six"] = 6
609
+ subject["six"].should == 6
610
+ should notify("must_only_ever_contain: Hash#[]=(\"six\", 6):"\
611
+ " pair {\"six\"=>6} does not match"\
612
+ " [{Symbol=>Integer, Integer=>Symbol}] in container {\"six\"=>6}")
613
+ end
614
+
615
+ it "should notify if inserting a matching value" do
616
+ subject[:six] = :six
617
+ subject[:six].should == :six
618
+ should notify
619
+ end
620
+
621
+ it "should not notify if inserting a non-matching pair" do
622
+ subject[:six] = 6
623
+ subject[:six].should == 6
624
+ should_not notify
625
+ end
626
+
627
+ it "should not notify if replaced with an acceptable hash" do
628
+ subject[:six] = 6
629
+ subject.replace({:sym => 343}).should == subject
630
+ subject[:six].should be_nil
631
+ subject[:sym].should == 343
632
+ should_not notify
633
+ end
634
+
635
+ it "should notify if merged with an unacceptable hash" do
636
+ subject.merge!({3 => 1})
637
+ should notify("must_only_ever_contain: Hash#merge!({3=>1}):"\
638
+ " pair {3=>1} does not match"\
639
+ " [{Symbol=>Integer, Integer=>Symbol}] in container {3=>1}")
640
+ end
641
+
642
+ it "should not notify if updated with an acceptable hash" do
643
+ subject.update({:yes => 1})
644
+ should_not notify
645
+ end
646
+
647
+ it "should notify if storing a matching key" do
648
+ subject.store(2.3, :float)
649
+ should notify
650
+ end
651
+ end
652
+
653
+ describe '#must_only_ever_contain_cases' do
654
+ before do
655
+ subject.must_only_ever_contain(Symbol => Symbol)
656
+ end
657
+
658
+ example "must_only_ever_contain_cases"\
659
+ " should == [{Symbol => Symbol}]" do
660
+ subject.must_only_ever_contain_cases.should == [{Symbol => Symbol}]
661
+ end
662
+
663
+ it "should not notify if inserting Symbol => Symbol pair" do
664
+ subject[:hello] = :granny
665
+ should_not notify
666
+ end
667
+
668
+ it "should notify if inserting Symbol => Integer pair" do
669
+ subject[:hello] = 970
670
+ should notify
671
+ end
672
+
673
+ it "should notify if inserting Integer => Integer pair" do
674
+ subject[3984] = 970
675
+ should notify("must_only_ever_contain: Hash#[]=(3984, 970):"\
676
+ " pair {3984=>970} does not match [{Symbol=>Symbol}] in"\
677
+ " container {3984=>970}")
678
+ end
679
+
680
+ context "when #must_only_ever_contain_cases is updated" do
681
+ let(:cases) { [{Symbol => Symbol}, {Symbol => Integer}] }
682
+
683
+ before do
684
+ subject.must_only_ever_contain_cases = cases
685
+ end
686
+
687
+ example "must_only_ever_contain_cases should =="\
688
+ " [{Symbol => Symbol}, {Symbol => Integer}]" do
689
+ subject.must_only_ever_contain_cases.should == cases
690
+ end
691
+
692
+ it "should not notify if inserting Symbol => Symbol pair" do
693
+ subject[:hello] = :granny
694
+ should_not notify
695
+ end
696
+
697
+ it "should not notify if inserting Symbol => Integer pair" do
698
+ subject[:hello] = 970
699
+ should_not notify
700
+ end
701
+
702
+ it "should notify if inserting Integer => Integer pair" do
703
+ subject[3984] = 970
704
+ should notify
705
+ end
706
+ end
707
+ end
708
+
709
+ context "when it is initially non-empty" do
710
+ before do
711
+ subject[:hello] = :world
712
+ end
713
+
714
+ it "should not notify if any cases match" do
715
+ subject.must_only_ever_contain(Symbol => Symbol)
716
+ should_not notify
717
+ end
718
+
719
+ it "should notify if cases do not match" do
720
+ subject.must_only_ever_contain(Symbol => String)
721
+ should notify("must_only_ever_contain: pair {:hello=>:world} does"\
722
+ " not match [{Symbol=>String}] in container {:hello=>:world}")
723
+ end
724
+ end
725
+ end
726
+
727
+ describe "custom" do
728
+ it_should_behave_like "custom MustOnlyEverContain"
729
+
730
+ context "without MustOnlyEverContain.registered_class" do
731
+ describe '#must_only_contain' do
732
+ it "should use each to check the contents" do
733
+ subject.must_only_contain(String)
734
+ subject.should be_each_called
735
+ should notify
736
+ end
737
+ end
738
+
739
+ describe '#must_only_ever_contain' do
740
+ it "should raise TypeError" do
741
+ expect do
742
+ subject.must_only_ever_contain(Symbol)
743
+ end.should raise_error(TypeError,
744
+ /No MustOnlyEverContain.registered_class for .*Box/)
745
+ end
746
+ end
747
+ end
748
+
749
+ context "with MustOnlyEverContain.registered_class" do
750
+ register_before_and_unregister_after
751
+
752
+ context "when subject already has singleton methods" do
753
+ it "should raise ArgumentError" do
754
+ expect do
755
+ class <<subject
756
+ def singleton_method
757
+ end
758
+ end
759
+ subject.must_only_ever_contain(Symbol)
760
+ end.should raise_error(ArgumentError,
761
+ /must_only_ever_contain adds singleton methods but receiver .*/)
762
+ end
763
+ end
764
+
765
+ context "when updating contents" do
766
+ it "should notify if does not match must_only_ever_contain_cases" do
767
+ subject.must_only_ever_contain(Symbol)
768
+ subject.contents = 435
769
+ should notify
770
+ end
771
+
772
+ it "should not notify if matches must_only_ever_contain_cases" do
773
+ subject.must_only_ever_contain(Symbol)
774
+ subject.contents = :another_symbol
775
+ should_not notify
776
+ end
777
+ end
778
+
779
+ context "when emptied" do
780
+ it "should notify if nil does not match"\
781
+ " must_only_ever_contain_cases" do
782
+ subject.must_only_ever_contain(Symbol)
783
+ subject.empty!
784
+ subject.should_not be_each_called
785
+ should notify
786
+ end
787
+ end
788
+
789
+ describe "when called with bad arguments" do
790
+ it "should raise when trying to register a non-class" do
791
+ expect do
792
+ MustOnlyEverContain.register(:not_a_class)
793
+ end.should raise_error(ArgumentError)
794
+ end
795
+
796
+ it "should raise when trying to register a class more than once" do
797
+ expect do
798
+ MustOnlyEverContain.register(Box)
799
+ end.should raise_error(ArgumentError)
800
+ end
801
+ end
802
+ end
803
+ end
804
+ end
805
+
806
+ describe '#must_never_ever_contain' do
807
+ context "when called on an array" do
808
+ subject { [nil] }
809
+
810
+ before do
811
+ subject.must_never_ever_contain
812
+ end
813
+
814
+ it "should notify if initially contains a matching member" do
815
+ array = [:oops]
816
+ array.must_never_ever_contain
817
+ should notify("must_never_ever_contain: :oops.must_not_be, but"\
818
+ " matches Symbol in container [:oops]")
819
+ end
820
+
821
+ describe '#<<' do
822
+ it "should not notify if obj is nil" do
823
+ subject << nil
824
+ should_not notify
825
+ end
826
+
827
+ it "should notify if obj is non-nil" do
828
+ subject << 5
829
+ should notify("must_never_ever_contain: Array#<<(5):"\
830
+ " 5.must_not_be, but matches Fixnum in container"\
831
+ " [nil, 5]")
832
+ end
833
+ end
834
+
835
+ describe '#collect!' do
836
+ it "should not notify if all new values are nil" do
837
+ subject.collect! {|v| v }
838
+ should_not notify
839
+ end
840
+
841
+ it "should notify if any new values are non-nil" do
842
+ subject.collect! {|v| 5 }
843
+ should notify
844
+ end
845
+ end
846
+ end
847
+
848
+ context "when called on a hash" do
849
+ subject { {} }
850
+
851
+ context "when called with a hash" do
852
+ before do
853
+ subject.must_never_ever_contain(Symbol => Integer,
854
+ Integer => Symbol)
855
+ end
856
+
857
+ it "should notify if inserting a non-matching value" do
858
+ subject[:six] = 6
859
+ subject[:six].should == 6
860
+ should notify
861
+ end
862
+
863
+ it "should not notify if inserting a matching pair" do
864
+ subject[:six] = :six
865
+ subject[:six].should == :six
866
+ should_not notify
867
+ end
868
+ end
869
+
870
+ context "when it is initially non-empty" do
871
+ before do
872
+ subject[:hello] = :world
873
+ end
874
+
875
+ it "should not notify if no cases match" do
876
+ subject.must_never_ever_contain(Symbol => String)
877
+ should_not notify
878
+ end
879
+
880
+ it "should notify if any cases match" do
881
+ subject.must_never_ever_contain(Symbol => Symbol)
882
+ should notify("must_never_ever_contain: pair {:hello=>:world}"\
883
+ " matches [{Symbol=>Symbol}] in container {:hello=>:world}")
884
+ end
885
+ end
886
+ end
887
+
888
+ describe "custom" do
889
+ it_should_behave_like "custom MustOnlyEverContain"
890
+
891
+ describe "without MustOnlyEverContain.registered_class" do
892
+ describe '#must_not_contain' do
893
+ it "should use each to check the contents" do
894
+ subject.must_not_contain(Symbol)
895
+ subject.should be_each_called
896
+ should notify
897
+ end
898
+ end
899
+
900
+ describe '#must_never_ever_contain' do
901
+ it "should raise TypeError" do
902
+ expect do
903
+ subject.must_never_ever_contain(String)
904
+ end.should raise_error(TypeError,
905
+ /No MustOnlyEverContain.registered_class for .*Box/)
906
+ end
907
+ end
908
+ end
909
+
910
+ describe "with MustOnlyEverContain.registered_class" do
911
+ register_before_and_unregister_after
912
+
913
+ context "when subject already has singleton methods" do
914
+ it "should raise ArgumentError" do
915
+ expect do
916
+ class <<subject
917
+ def singleton_method
918
+ end
919
+ end
920
+ subject.must_never_ever_contain(Symbol)
921
+ end.should raise_error(ArgumentError,
922
+ /must_never_ever_contain adds singleton methods but .*/)
923
+ end
924
+ end
925
+
926
+ context "when updating contents" do
927
+ it "should notify if matches must_only_ever_contain_cases" do
928
+ subject.must_only_ever_contain(Numeric)
929
+ subject.contents = 435
930
+ should notify
931
+ end
932
+
933
+ it "should not notify if does not match"\
934
+ " must_only_ever_contain_cases" do
935
+ subject.must_never_ever_contain(Numeric)
936
+ subject.contents = :another_symbol
937
+ should_not notify
938
+ end
939
+ end
940
+
941
+ context "when emptied" do
942
+ it "should notify if nil matches must_never_ever_contain_cases" do
943
+ subject.must_never_ever_contain(nil)
944
+ subject.empty!
945
+ subject.should_not be_each_called
946
+ should notify
947
+ end
948
+ end
949
+ end
950
+ end
951
+ end
952
+ end