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,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
|