dfect 0.0.0 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/lib/dfect.rb CHANGED
@@ -4,6 +4,18 @@
4
4
  #++
5
5
 
6
6
  require 'yaml'
7
+ #
8
+ # YAML raises this error when we try to serialize a class:
9
+ #
10
+ # TypeError: can't dump anonymous class Class
11
+ #
12
+ # Work around this by representing a class by its name.
13
+ #
14
+ class Class #:nodoc: all
15
+ def to_yaml opts = {}
16
+ name.to_yaml opts
17
+ end
18
+ end
7
19
 
8
20
  # load interactive debugger
9
21
  begin
@@ -110,6 +122,8 @@ module Dfect
110
122
  end
111
123
 
112
124
  ##
125
+ # :call-seq: <(&block)
126
+ #
113
127
  # Registers the given block to be executed
114
128
  # before each nested test inside this test.
115
129
  #
@@ -121,9 +135,14 @@ module Dfect
121
135
  # puts "before each nested test"
122
136
  # end
123
137
  #
124
- def < &block
125
- raise ArgumentError, 'block must be given' unless block
126
- @curr_suite.before_each << block
138
+ def <(*args, &block)
139
+ if args.empty?
140
+ raise ArgumentError, 'block must be given' unless block
141
+ @curr_suite.before_each << block
142
+ else
143
+ # the < method is being used as a check for inheritance
144
+ super
145
+ end
127
146
  end
128
147
 
129
148
  ##
@@ -192,7 +211,6 @@ module Dfect
192
211
  # # no message specified:
193
212
  #
194
213
  # T { true } # passes
195
- #
196
214
  # T { false } # fails
197
215
  # T { nil } # fails
198
216
  #
@@ -200,17 +218,8 @@ module Dfect
200
218
  #
201
219
  # T( "computers do not doublethink" ) { 2 + 2 != 5 } # passes
202
220
  #
203
- def T message = 'block must yield true (!nil && !false)', &block
204
- raise ArgumentError, 'block must be given' unless block
205
-
206
- if result = call(block)
207
- @exec_stats[:passed_assertions] += 1
208
- else
209
- @exec_stats[:failed_assertions] += 1
210
- debug block, message
211
- end
212
-
213
- result
221
+ def T message = nil, &block
222
+ assert_block :assert, message, &block
214
223
  end
215
224
 
216
225
  ##
@@ -227,31 +236,81 @@ module Dfect
227
236
  #
228
237
  # # no message specified:
229
238
  #
230
- # F { true } # fails
239
+ # T! { true } # fails
240
+ # T! { false } # passes
241
+ # T! { nil } # passes
242
+ #
243
+ # # message specified:
244
+ #
245
+ # T!( "computers do not doublethink" ) { 2 + 2 == 5 } # passes
231
246
  #
232
- # F { false } # passes
233
- # F { nil } # passes
247
+ def T! message = nil, &block
248
+ assert_block :negate, message, &block
249
+ end
250
+
251
+ ##
252
+ # Returns true if the result of the given block is
253
+ # neither nil nor false. Otherwise, returns false.
254
+ #
255
+ # ==== Parameters
256
+ #
257
+ # [message]
258
+ # This parameter is optional and completely ignored.
259
+ #
260
+ # ==== Examples
261
+ #
262
+ # # no message specified:
263
+ #
264
+ # T? { true } # => true
265
+ # T? { false } # => false
266
+ # T? { nil } # => false
234
267
  #
235
268
  # # message specified:
236
269
  #
237
- # F( "computers do not doublethink" ) { 2 + 2 == 5 } # passes
270
+ # T?( "computers do not doublethink" ) { 2 + 2 != 5 } # => true
238
271
  #
239
- def F message = 'block must yield false (nil || false)', &block
240
- raise ArgumentError, 'block must be given' unless block
272
+ def T? message = nil, &block
273
+ assert_block :sample, message, &block
274
+ end
241
275
 
242
- if result = call(block)
243
- @exec_stats[:failed_assertions] += 1
244
- debug block, message
245
- else
246
- @exec_stats[:passed_assertions] += 1
247
- end
276
+ alias F T!
248
277
 
249
- result
278
+ alias F! T
279
+
280
+ ##
281
+ # Returns true if the result of the given block is
282
+ # either nil or false. Otherwise, returns false.
283
+ #
284
+ # ==== Parameters
285
+ #
286
+ # [message]
287
+ # This parameter is optional and completely ignored.
288
+ #
289
+ # ==== Examples
290
+ #
291
+ # # no message specified:
292
+ #
293
+ # F? { true } # => false
294
+ # F? { false } # => true
295
+ # F? { nil } # => true
296
+ #
297
+ # # message specified:
298
+ #
299
+ # F?( "computers do not doublethink" ) { 2 + 2 == 5 } # => true
300
+ #
301
+ def F? message = nil, &block
302
+ not T? message, &block
250
303
  end
251
304
 
252
305
  ##
253
- # Asserts that one of the given kinds of exceptions is raised when the
254
- # given block is executed, and returns the exception that was raised.
306
+ # Asserts that one of the given
307
+ # kinds of exceptions is raised
308
+ # when the given block is executed.
309
+ #
310
+ # If the block raises an exception,
311
+ # then that exception is returned.
312
+ #
313
+ # Otherwise, nil is returned.
255
314
  #
256
315
  # ==== Parameters
257
316
  #
@@ -283,39 +342,95 @@ module Dfect
283
342
  # E( "string must compile", SyntaxError, NameError ) { eval "..." }
284
343
  #
285
344
  def E message = nil, *kinds, &block
286
- raise ArgumentError, 'block must be given' unless block
287
-
288
- if message.is_a? Class
289
- kinds.unshift message
290
- message = nil
291
- end
292
-
293
- kinds << StandardError if kinds.empty?
294
- message ||= "block must raise #{kinds.join ' or '}"
295
-
296
- begin
297
- block.call
298
-
299
- rescue *kinds => raised
300
- @exec_stats[:passed_assertions] += 1
301
-
302
- rescue Exception => raised
303
- @exec_stats[:failed_assertions] += 1
304
-
305
- # debug the uncaught exception...
306
- debug_uncaught_exception block, raised
345
+ assert_raise :assert, message, *kinds, &block
346
+ end
307
347
 
308
- # ...in addition to debugging this assertion
309
- debug block, [message, {'block raised' => raised}]
310
- end
348
+ ##
349
+ # Asserts that one of the given kinds of exceptions
350
+ # is not raised when the given block is executed.
351
+ #
352
+ # If the block raises an exception,
353
+ # then that exception is returned.
354
+ #
355
+ # Otherwise, nil is returned.
356
+ #
357
+ # ==== Parameters
358
+ #
359
+ # [message]
360
+ # Optional message to show in the
361
+ # report if this assertion fails.
362
+ #
363
+ # [kinds]
364
+ # Exception classes that must not be raised by the given block.
365
+ #
366
+ # If none are given, then StandardError is assumed (similar to how a
367
+ # plain 'rescue' statement without any arguments catches StandardError).
368
+ #
369
+ # ==== Examples
370
+ #
371
+ # # no exceptions specified:
372
+ #
373
+ # E! { } # passes
374
+ # E! { raise } # fails
375
+ #
376
+ # # single exception specified:
377
+ #
378
+ # E!( ArgumentError ) { raise ArgumentError } # fails
379
+ # E!( "argument must be invalid", ArgumentError ) { raise ArgumentError }
380
+ #
381
+ # # multiple exceptions specified:
382
+ #
383
+ # E!( SyntaxError, NameError ) { eval "..." }
384
+ # E!( "string must compile", SyntaxError, NameError ) { eval "..." }
385
+ #
386
+ def E! message = nil, *kinds, &block
387
+ assert_raise :negate, message, *kinds, &block
388
+ end
311
389
 
312
- raised
390
+ ##
391
+ # Returns true if one of the given kinds of
392
+ # exceptions is raised when the given block
393
+ # is executed. Otherwise, returns false.
394
+ #
395
+ # ==== Parameters
396
+ #
397
+ # [message]
398
+ # This parameter is optional and completely ignored.
399
+ #
400
+ # [kinds]
401
+ # Exception classes that must be raised by the given block.
402
+ #
403
+ # If none are given, then StandardError is assumed (similar to how a
404
+ # plain 'rescue' statement without any arguments catches StandardError).
405
+ #
406
+ # ==== Examples
407
+ #
408
+ # # no exceptions specified:
409
+ #
410
+ # E? { } # => false
411
+ # E? { raise } # => true
412
+ #
413
+ # # single exception specified:
414
+ #
415
+ # E?( ArgumentError ) { raise ArgumentError } # => true
416
+ #
417
+ # # multiple exceptions specified:
418
+ #
419
+ # E?( SyntaxError, NameError ) { eval "..." } # => true
420
+ #
421
+ def E? message = nil, *kinds, &block
422
+ assert_raise :sample, message, *kinds, &block
313
423
  end
314
424
 
315
425
  ##
316
- # Asserts that the given symbol is thrown when
317
- # the given block is executed, and returns the
318
- # value that was thrown along with the symbol.
426
+ # Asserts that the given symbol is thrown
427
+ # when the given block is executed.
428
+ #
429
+ # If a value is thrown along
430
+ # with the expected symbol,
431
+ # then that value is returned.
432
+ #
433
+ # Otherwise, nil is returned.
319
434
  #
320
435
  # ==== Parameters
321
436
  #
@@ -330,39 +445,75 @@ module Dfect
330
445
  #
331
446
  # # no message specified:
332
447
  #
333
- # C(:foo) { throw :foo } # passes
334
- #
335
- # C(:foo) { throw :bar } # fails
336
- # C(:foo) { } # fails
448
+ # C(:foo) { throw :foo, 123 } # passes, => 123
449
+ # C(:foo) { throw :bar, 456 } # fails, => 456
450
+ # C(:foo) { } # fails, => nil
337
451
  #
338
452
  # # message specified:
339
453
  #
340
- # C( ":foo must be thrown", :foo ) { throw :bar } # fails
454
+ # C( ":foo must be thrown", :foo ) { throw :bar, 789 } # fails, => nil
341
455
  #
342
456
  def C message = nil, symbol = nil, &block
343
- raise ArgumentError, 'block must be given' unless block
344
-
345
- if message.is_a? Symbol and not symbol
346
- symbol = message
347
- message = nil
348
- end
349
-
350
- raise ArgumentError, 'symbol must be given' unless symbol
351
-
352
- symbol = symbol.to_sym
353
- message ||= "block must throw #{symbol.inspect}"
457
+ assert_catch :assert, message, symbol, &block
458
+ end
354
459
 
355
- # if nothing was thrown, the result of catch()
356
- # is simply the result of executing the block
357
- result = catch(symbol) { call block; self }
460
+ ##
461
+ # Asserts that the given symbol is not
462
+ # thrown when the given block is executed.
463
+ #
464
+ # Returns nil, always.
465
+ #
466
+ # ==== Parameters
467
+ #
468
+ # [message]
469
+ # Optional message to show in the
470
+ # report if this assertion fails.
471
+ #
472
+ # [symbol]
473
+ # Symbol that must not be thrown by the given block.
474
+ #
475
+ # ==== Examples
476
+ #
477
+ # # no message specified:
478
+ #
479
+ # C!(:foo) { throw :foo, 123 } # fails, => nil
480
+ # C!(:foo) { throw :bar, 456 } # passes, => nil
481
+ # C!(:foo) { } # passes, => nil
482
+ #
483
+ # # message specified:
484
+ #
485
+ # C!( ":foo must be thrown", :foo ) { throw :bar, 789 } # passes, => nil
486
+ #
487
+ def C! message = nil, symbol = nil, &block
488
+ assert_catch :negate, message, symbol, &block
489
+ end
358
490
 
359
- if result == self
360
- @exec_stats[:failed_assertions] += 1
361
- debug block, message
362
- else
363
- @exec_stats[:passed_assertions] += 1
364
- result
365
- end
491
+ ##
492
+ # Returns true if the given symbol is thrown when the
493
+ # given block is executed. Otherwise, returns false.
494
+ #
495
+ # ==== Parameters
496
+ #
497
+ # [message]
498
+ # This parameter is optional and completely ignored.
499
+ #
500
+ # [symbol]
501
+ # Symbol that must be thrown by the given block.
502
+ #
503
+ # ==== Examples
504
+ #
505
+ # # no message specified:
506
+ #
507
+ # C?(:foo) { throw :foo, 123 } # => true
508
+ # C?(:foo) { throw :bar, 456 } # => false
509
+ # C?(:foo) { } # => false
510
+ #
511
+ # # message specified:
512
+ #
513
+ # C?( ":foo must be thrown", :foo ) { throw :bar, 789 } # => false
514
+ #
515
+ def C? message = nil, symbol = nil, &block
516
+ assert_catch :sample, message, symbol, &block
366
517
  end
367
518
 
368
519
  ##
@@ -393,6 +544,146 @@ module Dfect
393
544
 
394
545
  private
395
546
 
547
+ def assert_block mode, message = nil, &block
548
+ raise ArgumentError, 'block must be given' unless block
549
+
550
+ message ||=
551
+ case mode
552
+ when :assert then 'block must yield true (!nil && !false)'
553
+ when :negate then 'block must yield false (nil || false)'
554
+ end
555
+
556
+ passed = lambda do
557
+ @exec_stats[:passed_assertions] += 1
558
+ end
559
+
560
+ failed = lambda do
561
+ @exec_stats[:failed_assertions] += 1
562
+ debug block, message
563
+ end
564
+
565
+ result = call(block)
566
+
567
+ case mode
568
+ when :sample then return result ? true : false
569
+ when :assert then result ? passed.call : failed.call
570
+ when :negate then result ? failed.call : passed.call
571
+ end
572
+
573
+ result
574
+ end
575
+
576
+ def assert_raise mode, message = nil, *kinds, &block
577
+ raise ArgumentError, 'block must be given' unless block
578
+
579
+ if message.is_a? Class
580
+ kinds.unshift message
581
+ message = nil
582
+ end
583
+
584
+ kinds << StandardError if kinds.empty?
585
+
586
+ message ||=
587
+ case mode
588
+ when :assert then "block must raise #{kinds.join ' or '}"
589
+ when :negate then "block must not raise #{kinds.join ' or '}"
590
+ end
591
+
592
+ passed = lambda do
593
+ @exec_stats[:passed_assertions] += 1
594
+ end
595
+
596
+ failed = lambda do |exception|
597
+ @exec_stats[:failed_assertions] += 1
598
+
599
+ if exception
600
+ # debug the uncaught exception...
601
+ debug_uncaught_exception block, exception
602
+
603
+ # ...in addition to debugging this assertion
604
+ debug block, [message, {'block raised' => exception}]
605
+
606
+ else
607
+ debug block, message
608
+ end
609
+ end
610
+
611
+ begin
612
+ block.call
613
+
614
+ rescue Exception => exception
615
+ expected = kinds.any? {|k| exception.kind_of? k }
616
+
617
+ case mode
618
+ when :sample then return expected
619
+ when :assert then expected ? passed.call : failed.call(exception)
620
+ when :negate then expected ? failed.call(exception) : passed.call
621
+ end
622
+
623
+ else # nothing was raised
624
+ case mode
625
+ when :sample then return false
626
+ when :assert then failed.call nil
627
+ when :negate then passed.call
628
+ end
629
+ end
630
+
631
+ exception
632
+ end
633
+
634
+ def assert_catch mode, message = nil, symbol = nil, &block
635
+ raise ArgumentError, 'block must be given' unless block
636
+
637
+ if message.is_a? Symbol and not symbol
638
+ symbol = message
639
+ message = nil
640
+ end
641
+
642
+ raise ArgumentError, 'symbol must be given' unless symbol
643
+
644
+ symbol = symbol.to_sym
645
+ message ||= "block must throw #{symbol.inspect}"
646
+
647
+ passed = lambda do
648
+ @exec_stats[:passed_assertions] += 1
649
+ end
650
+
651
+ failed = lambda do
652
+ @exec_stats[:failed_assertions] += 1
653
+ debug block, message
654
+ end
655
+
656
+ # if nothing was thrown, the result of catch()
657
+ # is simply the result of executing the block
658
+ result = catch(symbol) do
659
+ begin
660
+ block.call
661
+
662
+ rescue Exception => e
663
+ debug_uncaught_exception block, e unless
664
+ # ignore error about the wrong symbol being thrown
665
+ #
666
+ # NOTE: Ruby 1.8 formats the thrown value in `quotes'
667
+ # whereas Ruby 1.9 formats it like a :symbol
668
+ #
669
+ e.message =~ /\Auncaught throw (`.*?'|:.*)\z/
670
+ end
671
+
672
+ self # unlikely that block will throw *this* object
673
+ end
674
+
675
+ caught = result != self
676
+ result = nil unless caught
677
+
678
+ case mode
679
+ when :sample then return caught
680
+ when :assert then caught ? passed.call : failed.call
681
+ when :negate then caught ? failed.call : passed.call
682
+ end
683
+
684
+ result
685
+ end
686
+
396
687
  ##
397
688
  # Executes the current test suite recursively.
398
689
  #
@@ -514,9 +805,16 @@ module Dfect
514
805
 
515
806
  # variable values
516
807
  'vars' => (
517
- locals = eval('::Kernel.local_variables.map {|v| [v.to_s, ::Kernel.eval(v.to_s)] }', context, __FILE__, __LINE__)
808
+ names = eval('::Kernel.local_variables', context, __FILE__, __LINE__)
809
+
810
+ pairs = names.inject([]) do |pair, name|
811
+ variable = name.to_s
812
+ value = eval(variable, context, __FILE__, __LINE__)
813
+
814
+ pair.push variable, value
815
+ end
518
816
 
519
- Hash[*locals.flatten]
817
+ Hash[*pairs]
520
818
  ),
521
819
 
522
820
  # stack trace
@@ -611,7 +909,7 @@ module Dfect
611
909
  D = self
612
910
 
613
911
  # provide mixin-able assertion methods
614
- methods(false).grep(/^[[:upper:]]$/).each do |name|
912
+ methods(false).grep(/^[[:upper:]][[:punct:]]?$/).each do |name|
615
913
  #
616
914
  # XXX: using eval() on a string because Ruby 1.8's
617
915
  # define_method() cannot take a block parameter
data/rakefile CHANGED
@@ -3,11 +3,13 @@
3
3
  # See the LICENSE file for details.
4
4
  #++
5
5
 
6
+ require 'rubygems'
7
+ gem 'inochi', '~> 1'
6
8
  require 'inochi'
7
9
 
8
10
  Inochi.init :Dfect,
9
- :version => '0.0.0',
10
- :release => '2009-04-13',
11
+ :version => '0.1.0',
12
+ :release => '2009-04-28',
11
13
  :website => 'http://snk.tuxfamily.org/lib/dfect',
12
14
  :tagline => 'Assertion testing library for Ruby'
13
15