dfect 0.0.0 → 0.1.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/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