must_be 1.0.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.
- data/.gitignore +2 -0
- data/README.md +348 -0
- data/Rakefile +27 -0
- data/VERSION +1 -0
- data/doc/readme/examples.rb +262 -0
- data/doc/readme/run_examples.rb +47 -0
- data/lib/must_be/attr_typed.rb +78 -0
- data/lib/must_be/basic.rb +120 -0
- data/lib/must_be/containers.rb +291 -0
- data/lib/must_be/containers_registered_classes.rb +83 -0
- data/lib/must_be/core.rb +247 -0
- data/lib/must_be/nonstandard_control_flow.rb +159 -0
- data/lib/must_be/proxy.rb +62 -0
- data/lib/must_be.rb +9 -0
- data/must_be.gemspec +71 -0
- data/spec/must_be/attr_typed_spec.rb +225 -0
- data/spec/must_be/basic_spec.rb +578 -0
- data/spec/must_be/containers_spec.rb +952 -0
- data/spec/must_be/core_spec.rb +675 -0
- data/spec/must_be/nonstandard_control_flow_spec.rb +845 -0
- data/spec/must_be/proxy_spec.rb +194 -0
- data/spec/notify_matcher_spec.rb +59 -0
- data/spec/spec_helper.rb +180 -0
- data/spec/typical_usage_spec.rb +176 -0
- metadata +98 -0
@@ -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
|