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.
@@ -0,0 +1,675 @@
1
+ require 'spec_helper'
2
+
3
+ describe MustBe do
4
+ include MustBeExampleHelper
5
+
6
+ ### Short Inspect ###
7
+
8
+ QUOTATION_MARKS = 2
9
+
10
+ describe ".short_inspect" do
11
+ it "should not shorten strings of length"\
12
+ " MustBe::SHORT_INSPECT_CUTOFF_LENGTH" do
13
+ s = "x" * (MustBe::SHORT_INSPECT_CUTOFF_LENGTH - QUOTATION_MARKS)
14
+ s.inspect.length.should == MustBe::SHORT_INSPECT_CUTOFF_LENGTH
15
+ si = MustBe.short_inspect(s)
16
+ si.should == s.inspect
17
+ end
18
+
19
+ it "should shorten strings longer than"\
20
+ " MustBe::SHORT_INSPECT_CUTOFF_LENGTH" do
21
+ s = "x" * MustBe::SHORT_INSPECT_CUTOFF_LENGTH
22
+ s.inspect.length.should == MustBe::SHORT_INSPECT_CUTOFF_LENGTH +
23
+ QUOTATION_MARKS
24
+ si = MustBe.short_inspect(s)
25
+ si.length.should == MustBe::SHORT_INSPECT_CUTOFF_LENGTH
26
+ end
27
+
28
+ it "should break at word boundries if possible" do
29
+ side_length = MustBe::SHORT_INSPECT_CUTOFF_LENGTH / 2
30
+ padding = "x" * (side_length - 7)
31
+ s = "#{padding} helloXXXXXworld #{padding}"
32
+ is = MustBe.short_inspect(s)
33
+ is.should match("xx ... xx")
34
+ end
35
+
36
+ it "should be used by MustBe" do
37
+ s = "x" * MustBe::SHORT_INSPECT_CUTOFF_LENGTH
38
+ s.must_be(Symbol)
39
+ should notify(/"x*\.\.\.x*"\.must_be\(Symbol\), but matches String/)
40
+ end
41
+ end
42
+
43
+ ### Enable ###
44
+
45
+ describe ".disable" do
46
+ before_disable_after_enable
47
+
48
+ it "should be disabled" do
49
+ MustBe.should_not be_enabled
50
+ end
51
+
52
+ example "#must_be should not notify" do
53
+ 5799.must_be(:lolly).should == 5799
54
+ should_not notify
55
+ end
56
+
57
+ example "#must_notify should return receiver (not a note)" do
58
+ 5799.must_notify("ignored message").should == 5799
59
+ should_not notify
60
+ end
61
+
62
+ example "#must_check should not yield to its block" do
63
+ yielded = false
64
+ must_check { yielded = true }
65
+ yielded.should be_false
66
+ end
67
+
68
+ example "#must should return receiver (not a proxy)" do
69
+ :delegate.must.object_id.should == :delegate.object_id
70
+ end
71
+
72
+ it "should be idempotent" do
73
+ MustBe.disable
74
+ MustBe.should_not be_enabled
75
+ end
76
+ end
77
+
78
+ describe ".enable" do
79
+ it "should start off enabled" do
80
+ MustBe.should be_enabled
81
+ end
82
+
83
+ context "after disabling" do
84
+ before_disable_and_reenable
85
+
86
+ it "should re-enable" do
87
+ MustBe.should be_enabled
88
+ end
89
+
90
+ example "#must_be should notify" do
91
+ 5799.must_be(:lolly).should == 5799
92
+ should notify("5799.must_be(:lolly), but matches Fixnum")
93
+ end
94
+
95
+ example "#must_notify should return a note" do
96
+ 5799.must_notify("noted message").should be_a(Note)
97
+ should notify("noted message")
98
+ end
99
+
100
+ example "#must_check should yield to its block" do
101
+ yielded = false
102
+ must_check { yielded = true }
103
+ yielded.should be_true
104
+ end
105
+
106
+ example "#must should return a proxy" do
107
+ :delegate.must.object_id.should_not == :delegate.object_id
108
+ end
109
+
110
+ it "should be idempotent" do
111
+ MustBe.enable
112
+ MustBe.should be_enabled
113
+ end
114
+ end
115
+ end
116
+
117
+ describe ".register_disabled_method" do
118
+ before :all do
119
+ module ::MustBe
120
+ def must_try_register_disabled_method
121
+ :enabled
122
+ end
123
+
124
+ def must_try_register_disabled_method__disabled
125
+ :disabled
126
+ end
127
+
128
+ register_disabled_method(
129
+ :must_try_register_disabled_method__disabled)
130
+
131
+ register_disabled_method(:must_try_register_disabled_method,
132
+ :must_try_register_disabled_method__disabled)
133
+ end
134
+ end
135
+
136
+ context "after disabling" do
137
+ before_disable_after_enable
138
+
139
+ example "#must_try_register_disabled_method should be disabled" do
140
+ must_try_register_disabled_method.should == :disabled
141
+ end
142
+ end
143
+
144
+ context "after re-enabling" do
145
+ before_disable_and_reenable
146
+
147
+ example "#must_try_register_disabled_method should return :enabled" do
148
+ must_try_register_disabled_method.should == :enabled
149
+ end
150
+ end
151
+ end
152
+
153
+ describe ".register_disabled_handler" do
154
+ before do
155
+ @original_disabled_handlers =
156
+ MustBe.send(:class_variable_get, :@@disabled_handlers).clone
157
+
158
+ @handler_called = nil
159
+ @handler = lambda do |enabled|
160
+ @handler_called = enabled
161
+ end
162
+ end
163
+
164
+ after do
165
+ MustBe.send(:class_variable_set, :@@disabled_handlers,
166
+ @original_disabled_handlers)
167
+ end
168
+
169
+ context "when initially enabled" do
170
+ before do
171
+ MustBe.register_disabled_handler(&@handler)
172
+ end
173
+
174
+ example "handler should not be called immediately" do
175
+ @handler_called.should be_nil
176
+ end
177
+
178
+ context "when disabled" do
179
+ before_disable_after_enable
180
+
181
+ example "handler should be called" do
182
+ @handler_called.should be_false
183
+ end
184
+ end
185
+ end
186
+
187
+ context "when initially disabled" do
188
+ before_disable_after_enable
189
+
190
+ before do
191
+ MustBe.register_disabled_handler(&@handler)
192
+ end
193
+
194
+ example "handler should be called immediately" do
195
+ @handler_called.should be_false
196
+ end
197
+
198
+ context "when enabled" do
199
+ before do
200
+ MustBe.enable
201
+ end
202
+
203
+ example "handler should be called" do
204
+ @handler_called.should be_true
205
+ end
206
+ end
207
+ end
208
+ end
209
+
210
+ describe '#must_just_return' do
211
+ it "should return the receiver" do
212
+ :gnarly.must_just_return(:args, :ignored).should == :gnarly
213
+ should_not notify
214
+ end
215
+ end
216
+
217
+ describe '#must_just_yield' do
218
+ it "should yield" do
219
+ did_yield = false
220
+ must_just_yield { did_yield = true }
221
+ did_yield.should be_true
222
+ should_not notify
223
+ end
224
+ end
225
+
226
+ ### Notifiers ###
227
+
228
+ describe "default notifier" do
229
+ it "should be RaiseNotifier" do
230
+ $default_must_be_notifier.should == MustBe::RaiseNotifier
231
+ end
232
+ end
233
+
234
+ describe "other built-in notifiers" do
235
+ before do
236
+ @original_notifier = MustBe.notifier
237
+ MustBe.notifier = notifier
238
+
239
+ @original_stdout = $stdout
240
+ $stdout = StringIO.new
241
+ end
242
+
243
+ after do
244
+ MustBe.notifier = @original_notifier
245
+ $stdout = @original_stdout
246
+ end
247
+
248
+ describe 'LogNotifier' do
249
+ let(:notifier) { LogNotifier }
250
+
251
+ it "should puts message and backtrace" do
252
+ 3.must_be(4)
253
+
254
+ $stdout.string.should match(
255
+ /3.must_be\(4\), but matches Fixnum\n\t.*core_spec.rb:\d+.*\n\t/)
256
+ end
257
+ end
258
+
259
+ describe 'DebugNotifier' do
260
+ let(:notifier) { DebugNotifier }
261
+
262
+ before do
263
+ $" << 'ruby-debug' # to keep ruby-debug from being loaded.
264
+
265
+ $must_be__did_call_debugger = false
266
+ def MustBe.debugger
267
+ $must_be__did_call_debugger = true
268
+ end
269
+ end
270
+
271
+ after do
272
+ class <<MustBe
273
+ remove_method :debugger
274
+ end
275
+ end
276
+
277
+ it "should puts a message, store the note in $must_be__note,"\
278
+ " and call the debugger" do
279
+ 3.must_be(4)
280
+
281
+ $stdout.string.should == "3.must_be(4), but matches Fixnum\n"\
282
+ "Starting debugger ($must_be__note stores the note)...\n"
283
+ $must_be__note.message.should == "3.must_be(4), but matches Fixnum"
284
+ $must_be__did_call_debugger.should be_true
285
+ end
286
+ end
287
+ end
288
+
289
+ describe ".set_notifier_from_env" do
290
+ before do
291
+ $notifier = MustBe.notifier
292
+ end
293
+
294
+ after do
295
+ MustBe.notifier = $notifier
296
+ end
297
+
298
+ it "should use 'log' to set the LogNotifier" do
299
+ MustBe.set_notifier_from_env('log')
300
+ MustBe.notifier.should == MustBe::LogNotifier
301
+ end
302
+
303
+ it "should use ENV['MUST_BE__NOTIFIER'] when no argument provided" do
304
+ ENV['MUST_BE__NOTIFIER'] = 'debug'
305
+ MustBe.set_notifier_from_env
306
+ MustBe.notifier.should == MustBe::DebugNotifier
307
+ end
308
+
309
+ it "should raise NoMethodError when argument does not respond to :to_sym" do
310
+ expect do
311
+ MustBe.set_notifier_from_env(nil)
312
+ end.should raise_error(NoMethodError)
313
+ end
314
+
315
+ it "should raise ArgumentError when unknown notifier name provided" do
316
+ expect do
317
+ MustBe.set_notifier_from_env(:unknown)
318
+ end.should raise_error(ArgumentError)
319
+ end
320
+
321
+ it "should treat 'disable' as a special case" do
322
+ MustBe.set_notifier_from_env('disable')
323
+ MustBe.should_not be_enabled
324
+ MustBe.notifier.should == $notifier
325
+ MustBe.enable
326
+ MustBe.should be_enabled
327
+ end
328
+ end
329
+
330
+ describe ".def_notifier" do
331
+ context "when called with a key" do
332
+ before :all do
333
+ MustBe.def_notifier(:Spec__ExampleNotifier, :spec__example) {}
334
+ end
335
+
336
+ it "should set a constant" do
337
+ MustBe::Spec__ExampleNotifier.should be_a(Proc)
338
+ end
339
+
340
+ it "should add the key to NOTIFIERS" do
341
+ MustBe::NOTIFIERS[:spec__example].should == :Spec__ExampleNotifier
342
+ end
343
+
344
+ it "should extend .set_notifier_from_env" do
345
+ MustBe.set_notifier_from_env(:spec__example)
346
+ MustBe.notifier.should == MustBe::Spec__ExampleNotifier
347
+ end
348
+ end
349
+
350
+ context "when called with no key" do
351
+ before :all do
352
+ @original_notifiers = MustBe::NOTIFIERS.clone
353
+
354
+ MustBe.def_notifier(:Spec__SecondExampleNotifier) {}
355
+ end
356
+
357
+ it "should set a constant" do
358
+ MustBe::Spec__SecondExampleNotifier.should be_a(Proc)
359
+ end
360
+
361
+ it "should leave NOTIFIERS unchanged" do
362
+ MustBe::NOTIFIERS.should == @original_notifiers
363
+ end
364
+ end
365
+ end
366
+
367
+ describe "RaiseNotifier" do
368
+ before do
369
+ MustBe.notifier = RaiseNotifier
370
+ end
371
+
372
+ it "should raise Note" do
373
+ expect do
374
+ must_notify("funny bunny")
375
+ end.should(raise_error(Note, "funny bunny") do |note|
376
+ note.backtrace[0].should_not match(/`must_notify'/)
377
+ end)
378
+ end
379
+ end
380
+
381
+ ### Note ###
382
+
383
+ describe "Note" do
384
+ # #must_notify provides examples covering #initialize and #to_s.
385
+
386
+ describe "difference between #backtrace and #complete_backtrace" do
387
+ example "#backtrace should drop lines containing %r{lib/must_be.*\\.rb:}"\
388
+ " from #complete_backtrace" do
389
+ backtrace = [
390
+ "first line kept",
391
+ "other lib/must_be.rb: kept as well"]
392
+
393
+ complete_backtrace = [
394
+ "lib/must_be.rb: at start",
395
+ "in middle lib/must_be_elsewhere.rb: is okay",
396
+ "at end too lib/must_be_yet_again.rb:",
397
+ *backtrace]
398
+
399
+ note = Note.new("sample")
400
+ note.set_backtrace(complete_backtrace)
401
+
402
+ note.complete_backtrace.should == complete_backtrace
403
+ note.backtrace.should == backtrace
404
+ end
405
+ end
406
+ end
407
+
408
+ describe '#must_notify' do
409
+ class <<self
410
+ def it_should_notify(message)
411
+ its(:message) { should == message }
412
+ it("should notify") { should notify(message) }
413
+ end
414
+
415
+ def its_assertion_properties_should_be_nil
416
+ its(:receiver) { should be_nil }
417
+ its(:assertion) { should be_nil }
418
+ its(:args) { should be_nil }
419
+ its(:block) { should be_nil }
420
+ its(:additional_message) { should be_nil }
421
+ end
422
+ end
423
+
424
+ block = lambda { nil }
425
+
426
+ context "when called with no arguments" do
427
+ subject { must_notify }
428
+ it_should_notify("MustBe::Note")
429
+ its_assertion_properties_should_be_nil
430
+ end
431
+
432
+ context "when called with single (message) argument" do
433
+ subject { must_notify("message for note") }
434
+ it_should_notify("message for note")
435
+ its_assertion_properties_should_be_nil
436
+ end
437
+
438
+ context "when called with existing note" do
439
+ note = Note.new("existing note")
440
+
441
+ subject { must_notify(note) }
442
+ it_should_notify("existing note")
443
+ it { should == note }
444
+ end
445
+
446
+ context "when called with receiver and assertion" do
447
+ subject { must_notify(4890, :must_be_silly) }
448
+ it_should_notify("4890.must_be_silly")
449
+ its(:receiver) { should == 4890 }
450
+ its(:assertion) { should == :must_be_silly }
451
+ its(:args) { should be_nil }
452
+ its(:block) { should be_nil }
453
+ end
454
+
455
+ context "when called with receiver, assertion, and an argument" do
456
+ subject { must_notify(4890, :must_be_silly, [57]) }
457
+ it_should_notify("4890.must_be_silly(57)")
458
+ its(:receiver) { should == 4890 }
459
+ its(:assertion) { should == :must_be_silly }
460
+ its(:args) { should == [57] }
461
+ its(:block) { should be_nil }
462
+ end
463
+
464
+ context "when called with receiver, assertion, and arguments" do
465
+ subject { must_notify(4890, :must_be_silly, [57, 71]) }
466
+ it_should_notify("4890.must_be_silly(57, 71)")
467
+ its(:receiver) { should == 4890 }
468
+ its(:assertion) { should == :must_be_silly }
469
+ its(:args) { should == [57, 71] }
470
+ its(:block) { should be_nil }
471
+ end
472
+
473
+ context "when called with receiver, assertion, and block" do
474
+ block = lambda { nil }
475
+
476
+ subject { must_notify(4890, :must_be_silly, nil, block) }
477
+ it_should_notify("4890.must_be_silly {}")
478
+ its(:receiver) { should == 4890 }
479
+ its(:assertion) { should == :must_be_silly }
480
+ its(:args) { should == nil }
481
+ its(:block) { should == block }
482
+ end
483
+
484
+ context "when called with receiver, assertion, arguments, and block" do
485
+ subject { must_notify(4890, :must_be_silly, [57, 71], block) }
486
+ it_should_notify("4890.must_be_silly(57, 71) {}")
487
+ its(:receiver) { should == 4890 }
488
+ its(:assertion) { should == :must_be_silly }
489
+ its(:args) { should == [57, 71] }
490
+ its(:block) { should == block }
491
+ end
492
+
493
+ context "when called with #additional_message" do
494
+ subject do
495
+ must_notify(5, :must_be, [String], nil, ", but matches Fixnum")
496
+ end
497
+
498
+ it_should_notify("5.must_be(String), but matches Fixnum")
499
+ its(:receiver) { should == 5 }
500
+ its(:assertion) { should == :must_be }
501
+ its(:args) { should == [String] }
502
+ its(:block) { should be_nil }
503
+ its(:additional_message) { should == ", but matches Fixnum"}
504
+ end
505
+ end
506
+
507
+ describe '#must_check' do
508
+ context "when its block attempts to notify" do
509
+ it "should return the note without notifying" do
510
+ note = must_check do
511
+ must_notify("ignored note")
512
+ must_notify("returned note")
513
+ "extra stuff"
514
+ end
515
+ should_not notify
516
+ note.should be_a(Note)
517
+ note.message.should == "returned note"
518
+ end
519
+ end
520
+
521
+ context "when its block does not notify" do
522
+ it "should return nil" do
523
+ did_yield = false
524
+ note = must_check { did_yield = true }
525
+ did_yield.should be_true
526
+ should_not notify
527
+ note.should == nil
528
+ end
529
+ end
530
+
531
+ context "when called with a proc" do
532
+ it "should not call its block if the proc does not notify" do
533
+ did_call_block = false
534
+ must_check(lambda {}) do
535
+ did_call_block = true
536
+ end
537
+ did_call_block.should be_false
538
+ end
539
+
540
+ it "should call its block and notify if the proc notifies" do
541
+ did_call_block = false
542
+ must_check(lambda { must_notify("check") }) do |note|
543
+ did_call_block = true
544
+ note.message.should == "check"
545
+ Note.new("mate")
546
+ end
547
+ did_call_block.should be_true
548
+ should notify("mate")
549
+ end
550
+
551
+ it "should use the result of the proc to generate a new note" do
552
+ did_call_block = false
553
+ must_check(lambda { must_notify("check") }) do |note|
554
+ did_call_block = true
555
+ note.message.should == "check"
556
+ "mate"
557
+ end
558
+ did_call_block.should be_true
559
+ should notify("mate")
560
+ end
561
+ end
562
+
563
+ context "when nesting" do
564
+ it "should be safe" do
565
+ note = must_check do
566
+ inner_note = must_check { must_notify("inner") }
567
+ should_not notify
568
+ inner_note.message.should == "inner"
569
+
570
+ must_notify("outer")
571
+ end
572
+ should_not notify
573
+ note.message.should == "outer"
574
+ end
575
+
576
+ it "should ignore inner checked notes" do
577
+ note = must_check do
578
+ must_notify("outer")
579
+ must_check { must_notify("inner") }
580
+ end
581
+ should_not notify
582
+ note.message.should == "outer"
583
+ end
584
+
585
+ it "should return nil if all inner notes are also checked" do
586
+ note = must_check do
587
+ must_check { must_notify("inner") }
588
+ end
589
+ should_not notify
590
+ note.should == nil
591
+ end
592
+ end
593
+
594
+ describe "safety" do
595
+ it "should be able to be called multiple times" do
596
+ note = must_check { must_notify("once") }
597
+ should_not notify
598
+ note.message.should == "once"
599
+
600
+ note = must_check { must_notify("again") }
601
+ should_not notify
602
+ note.message.should == "again"
603
+ end
604
+
605
+ it "should be error safe" do
606
+ expect do
607
+ must_check do
608
+ raise
609
+ end
610
+ end.should raise_error
611
+
612
+ must_notify
613
+ should notify
614
+ end
615
+
616
+ it "should be thread safe" do
617
+ mutex = Mutex.new
618
+ cv = ConditionVariable.new
619
+
620
+ cv_yield = lambda do
621
+ cv.signal
622
+ cv.wait(mutex)
623
+ end
624
+
625
+ thread = nil
626
+ thread_note = nil
627
+ note = nil
628
+
629
+ thread_block = lambda do
630
+ mutex.synchronize do
631
+ thread_note = must_check do
632
+ must_notify("thread")
633
+ cv_yield[]
634
+ end
635
+ end
636
+ end
637
+
638
+ mutex.synchronize do
639
+ note = must_check do
640
+ must_notify("main")
641
+ thread = Thread.new &thread_block
642
+ cv_yield[]
643
+ end
644
+ cv.signal
645
+ end
646
+ thread.join
647
+
648
+ note.message.should == "main"
649
+ thread_note.message.should == "thread"
650
+ end
651
+
652
+ if RUBY_VERSION > "1.9"
653
+ it "should be fiber safe" do
654
+ fiber_note = nil
655
+
656
+ fiber = Fiber.new do
657
+ fiber_note = must_check do
658
+ must_notify("fiber")
659
+ Fiber.yield
660
+ end
661
+ end
662
+
663
+ note = must_check do
664
+ must_notify("main")
665
+ fiber.resume
666
+ end
667
+ fiber.resume
668
+
669
+ note.message.should == "main"
670
+ fiber_note.message.should == "fiber"
671
+ end
672
+ end
673
+ end
674
+ end
675
+ end