nullstyle-test-spec 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,660 @@
1
+ #
2
+ # test/spec -- a BDD interface for Test::Unit
3
+ #
4
+ # Copyright (C) 2006, 2007 Christian Neukirchen <mailto:chneukirchen@gmail.com>
5
+ #
6
+ # This work is licensed under the same terms as Ruby itself.
7
+ #
8
+
9
+ require 'test/unit'
10
+
11
+ class Test::Unit::AutoRunner # :nodoc:
12
+ RUNNERS[:specdox] = lambda {
13
+ require 'test/spec/dox'
14
+ Test::Unit::UI::SpecDox::TestRunner
15
+ }
16
+
17
+ RUNNERS[:rdox] = lambda {
18
+ require 'test/spec/rdox'
19
+ Test::Unit::UI::RDox::TestRunner
20
+ }
21
+ end
22
+
23
+ module Test # :nodoc:
24
+ end
25
+
26
+ module Test::Spec
27
+ require 'test/spec/version'
28
+
29
+ CONTEXTS = {} # :nodoc:
30
+ SHARED_CONTEXTS = Hash.new { |h,k| h[k] = [] } # :nodoc:
31
+
32
+ class DefinitionError < StandardError
33
+ end
34
+
35
+ class Should
36
+ include Test::Unit::Assertions
37
+
38
+ def self.deprecated_alias(to, from) # :nodoc:
39
+ define_method(to) { |*args|
40
+ warn "Test::Spec::Should##{to} is deprecated and will be removed in future versions."
41
+ __send__ from, *args
42
+ }
43
+ end
44
+
45
+ def initialize(object, message=nil)
46
+ @object = object
47
+ @message = message
48
+ end
49
+
50
+ $TEST_SPEC_TESTCASE = nil
51
+ def add_assertion
52
+ $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
53
+ end
54
+
55
+
56
+ def an
57
+ self
58
+ end
59
+
60
+ def a
61
+ self
62
+ end
63
+
64
+ def not(*args)
65
+ case args.size
66
+ when 0
67
+ ShouldNot.new(@object, @message)
68
+ when 1
69
+ ShouldNot.new(@object, @message).pass(args.first)
70
+ else
71
+ raise ArgumentError, "#not takes zero or one argument(s)."
72
+ end
73
+ end
74
+
75
+ def messaging(message)
76
+ @message = message.to_s
77
+ self
78
+ end
79
+ alias blaming messaging
80
+
81
+ def satisfy(&block)
82
+ assert_block(@message || "satisfy block failed.") {
83
+ yield @object
84
+ }
85
+ end
86
+
87
+ def equal(value)
88
+ assert_equal value, @object, @message
89
+ end
90
+ alias == equal
91
+
92
+ def close(value, delta)
93
+ assert_in_delta value, @object, delta, @message
94
+ end
95
+ deprecated_alias :be_close, :close
96
+
97
+ def be(*value)
98
+ case value.size
99
+ when 0
100
+ self
101
+ when 1
102
+ if CustomShould === value.first
103
+ pass value.first
104
+ else
105
+ assert_same value.first, @object, @message
106
+ end
107
+ else
108
+ raise ArgumentError, "should.be needs zero or one argument"
109
+ end
110
+ end
111
+
112
+ def match(value)
113
+ assert_match value, @object, @message
114
+ end
115
+ alias =~ match
116
+
117
+ def instance_of(klass)
118
+ assert_instance_of klass, @object, @message
119
+ end
120
+ deprecated_alias :be_an_instance_of, :instance_of
121
+
122
+ def kind_of(klass)
123
+ assert_kind_of klass, @object, @message
124
+ end
125
+ deprecated_alias :be_a_kind_of, :kind_of
126
+
127
+ def respond_to(method)
128
+ assert_respond_to @object, method, @message
129
+ end
130
+
131
+ def _raise(*args, &block)
132
+ args = [RuntimeError] if args.empty?
133
+ block ||= @object
134
+ assert_raise(*(args + [@message]), &block)
135
+ end
136
+
137
+ def throw(*args)
138
+ assert_throws(*(args + [@message]), &@object)
139
+ end
140
+
141
+ def nil
142
+ assert_nil @object, @message
143
+ end
144
+ deprecated_alias :be_nil, :nil
145
+
146
+
147
+ def include(value)
148
+ msg = build_message(@message, "<?> expected to include ?, but it didn't.",
149
+ @object, value)
150
+ assert_block(msg) { @object.include?(value) }
151
+ end
152
+
153
+ def >(value)
154
+ assert_operator @object, :>, value, @message
155
+ end
156
+
157
+ def >=(value)
158
+ assert_operator @object, :>=, value, @message
159
+ end
160
+
161
+ def <(value)
162
+ assert_operator @object, :<, value, @message
163
+ end
164
+
165
+ def <=(value)
166
+ assert_operator @object, :<=, value, @message
167
+ end
168
+
169
+ def ===(value)
170
+ assert_operator @object, :===, value, @message
171
+ end
172
+
173
+ def pass(custom)
174
+ _wrap_assertion {
175
+ assert_nothing_raised(Test::Unit::AssertionFailedError,
176
+ @message || custom.failure_message) {
177
+ assert custom.matches?(@object), @message || custom.failure_message
178
+ }
179
+ }
180
+ end
181
+
182
+ def method_missing(name, *args, &block)
183
+ # This will make raise call Kernel.raise, and self.raise call _raise.
184
+ return _raise(*args, &block) if name == :raise
185
+
186
+ if @object.respond_to?("#{name}?")
187
+ assert @object.__send__("#{name}?", *args),
188
+ "#{name}? expected to be true. #{@message}"
189
+ else
190
+ if @object.respond_to?(name)
191
+ assert @object.__send__(name, *args),
192
+ "#{name} expected to be true. #{@message}"
193
+ else
194
+ super
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ class ShouldNot
201
+ include Test::Unit::Assertions
202
+
203
+ def initialize(object, message=nil)
204
+ @object = object
205
+ @message = message
206
+ end
207
+
208
+ def add_assertion
209
+ $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
210
+ end
211
+
212
+
213
+ def satisfy(&block)
214
+ assert_block(@message || "not.satisfy block succeded.") {
215
+ not yield @object
216
+ }
217
+ end
218
+
219
+ def equal(value)
220
+ assert_not_equal value, @object, @message
221
+ end
222
+ alias == equal
223
+
224
+ def be(*value)
225
+ case value.size
226
+ when 0
227
+ self
228
+ when 1
229
+ if CustomShould === value.first
230
+ pass value.first
231
+ else
232
+ assert_not_same value.first, @object, @message
233
+ end
234
+ else
235
+ Kernel.raise ArgumentError, "should.be needs zero or one argument"
236
+ end
237
+ end
238
+
239
+ def match(value)
240
+ # Icky Regexp check
241
+ assert_no_match value, @object, @message
242
+ end
243
+ alias =~ match
244
+
245
+ def _raise(*args, &block)
246
+ block ||= @object
247
+ assert_nothing_raised(*(args+[@message]), &block)
248
+ end
249
+
250
+ def throw
251
+ assert_nothing_thrown(@message, &@object)
252
+ end
253
+
254
+ def nil
255
+ assert_not_nil @object, @message
256
+ end
257
+
258
+ def be_nil
259
+ warn "Test::Spec::ShouldNot#be_nil is deprecated and will be removed in future versions."
260
+ self.nil
261
+ end
262
+
263
+ def not(*args)
264
+ case args.size
265
+ when 0
266
+ Should.new(@object, @message)
267
+ when 1
268
+ Should.new(@object, @message).pass(args.first)
269
+ else
270
+ raise ArgumentError, "#not takes zero or one argument(s)."
271
+ end
272
+ end
273
+
274
+ def pass(custom)
275
+ _wrap_assertion {
276
+ begin
277
+ assert !custom.matches?(@object), @message || custom.failure_message
278
+ end
279
+ }
280
+ end
281
+
282
+ def method_missing(name, *args, &block)
283
+ # This will make raise call Kernel.raise, and self.raise call _raise.
284
+ return _raise(*args, &block) if name == :raise
285
+
286
+ if @object.respond_to?("#{name}?")
287
+ assert_block("#{name}? expected to be false. #{@message}") {
288
+ not @object.__send__("#{name}?", *args)
289
+ }
290
+ else
291
+ if @object.respond_to?(name)
292
+ assert_block("#{name} expected to be false. #{@message}") {
293
+ not @object.__send__("#{name}", *args)
294
+ }
295
+ else
296
+ super
297
+ end
298
+ end
299
+ end
300
+
301
+ end
302
+
303
+ class CustomShould
304
+ attr_accessor :object
305
+
306
+ def initialize(obj)
307
+ self.object = obj
308
+ end
309
+
310
+ def failure_message
311
+ "#{self.class.name} failed"
312
+ end
313
+
314
+ def matches?(*args, &block)
315
+ assumptions(*args, &block)
316
+ true
317
+ end
318
+
319
+ def assumptions(*args, &block)
320
+ raise NotImplementedError, "you need to supply a #{self.class}#matches? method"
321
+ end
322
+ end
323
+ end
324
+
325
+ class Test::Spec::TestCase
326
+ attr_reader :testcase
327
+ attr_reader :name
328
+ attr_reader :position
329
+
330
+ module InstanceMethods
331
+ def setup # :nodoc:
332
+ $TEST_SPEC_TESTCASE = self
333
+ super
334
+ call_methods_including_parents(:setups)
335
+ end
336
+
337
+ def teardown # :nodoc:
338
+ super
339
+ call_methods_including_parents(:teardowns, :reverse)
340
+ end
341
+
342
+ def before_all
343
+ call_methods_including_parents(:before_all)
344
+ end
345
+
346
+ def after_all
347
+ call_methods_including_parents(:after_all, :reverse)
348
+ end
349
+
350
+ def initialize(name)
351
+ super name
352
+
353
+ # Don't let the default_test clutter up the results and don't
354
+ # flunk if no tests given, either.
355
+ throw :invalid_test if name.to_s == "default_test"
356
+ end
357
+
358
+ def position
359
+ self.class.position
360
+ end
361
+
362
+ def context(*args)
363
+ raise Test::Spec::DefinitionError,
364
+ "context definition is not allowed inside a specify-block"
365
+ end
366
+
367
+ alias :describe :context
368
+
369
+ private
370
+
371
+ def call_methods_including_parents(method, reverse=false, klass=self.class)
372
+ return unless klass
373
+
374
+ if reverse
375
+ klass.send(method).each { |s| instance_eval(&s) }
376
+ call_methods_including_parents(method, reverse, klass.parent)
377
+ else
378
+ call_methods_including_parents(method, reverse, klass.parent)
379
+ klass.send(method).each { |s| instance_eval(&s) }
380
+ end
381
+ end
382
+ end
383
+
384
+ module ClassMethods
385
+ attr_accessor :count
386
+ attr_accessor :name
387
+ attr_accessor :position
388
+ attr_accessor :parent
389
+
390
+ attr_accessor :setups
391
+ attr_accessor :teardowns
392
+
393
+ attr_accessor :before_all
394
+ attr_accessor :after_all
395
+
396
+ # old-style (RSpec <1.0):
397
+
398
+ def context(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block)
399
+ (Test::Spec::CONTEXTS[self.name + "\t" + name] ||= klass.new(name, self, superclass)).add(&block)
400
+ end
401
+
402
+ def xcontext(name, superclass=Test::Unit::TestCase, &block)
403
+ context(name, superclass, Test::Spec::DisabledTestCase, &block)
404
+ end
405
+
406
+ def specify(specname, &block)
407
+ xspecify(specname) and return if block.nil?
408
+
409
+ self.count += 1 # Let them run in order of definition
410
+
411
+ define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block)
412
+ end
413
+
414
+ def xspecify(specname, &block)
415
+ specify specname do
416
+ @_result.add_disabled(specname)
417
+ end
418
+ end
419
+
420
+ def setup(&block)
421
+ setups << block
422
+ end
423
+
424
+ def teardown(&block)
425
+ teardowns << block
426
+ end
427
+
428
+ def shared_context(name, &block)
429
+ Test::Spec::SHARED_CONTEXTS[self.name + "\t" + name] << block
430
+ end
431
+
432
+ def behaves_like(shared_context)
433
+ if Test::Spec::SHARED_CONTEXTS.include?(shared_context)
434
+ Test::Spec::SHARED_CONTEXTS[shared_context].each { |block|
435
+ instance_eval(&block)
436
+ }
437
+ elsif Test::Spec::SHARED_CONTEXTS.include?(self.name + "\t" + shared_context)
438
+ Test::Spec::SHARED_CONTEXTS[self.name + "\t" + shared_context].each { |block|
439
+ instance_eval(&block)
440
+ }
441
+ else
442
+ raise NameError, "Shared context #{shared_context} not found."
443
+ end
444
+ end
445
+ alias :it_should_behave_like :behaves_like
446
+
447
+ # new-style (RSpec 1.0+):
448
+
449
+ alias :describe :context
450
+ alias :describe_shared :shared_context
451
+ alias :it :specify
452
+ alias :xit :xspecify
453
+
454
+ def before(kind=:each, &block)
455
+ case kind
456
+ when :each
457
+ setup(&block)
458
+ when :all
459
+ before_all << block
460
+ else
461
+ raise ArgumentError, "invalid argument: before(#{kind.inspect})"
462
+ end
463
+ end
464
+
465
+ def after(kind=:each, &block)
466
+ case kind
467
+ when :each
468
+ teardown(&block)
469
+ when :all
470
+ after_all << block
471
+ else
472
+ raise ArgumentError, "invalid argument: after(#{kind.inspect})"
473
+ end
474
+ end
475
+
476
+
477
+ def init(name, position, parent)
478
+ self.position = position
479
+ self.parent = parent
480
+
481
+ if parent
482
+ self.name = parent.name + "\t" + name
483
+ else
484
+ self.name = name
485
+ end
486
+
487
+ self.count = 0
488
+ self.setups = []
489
+ self.teardowns = []
490
+
491
+ self.before_all = []
492
+ self.after_all = []
493
+ end
494
+ end
495
+
496
+ @@POSITION = 0
497
+
498
+ def initialize(name, parent=nil, superclass=Test::Unit::TestCase)
499
+ @testcase = Class.new(superclass) {
500
+ include InstanceMethods
501
+ extend ClassMethods
502
+ }
503
+
504
+ @@POSITION = @@POSITION + 1
505
+ @testcase.init(name, @@POSITION, parent)
506
+ end
507
+
508
+ def add(&block)
509
+ raise ArgumentError, "context needs a block" if block.nil?
510
+
511
+ @testcase.class_eval(&block)
512
+ self
513
+ end
514
+ end
515
+
516
+ (Test::Spec::DisabledTestCase = Test::Spec::TestCase.dup).class_eval do
517
+ alias :test_case_initialize :initialize
518
+
519
+ def initialize(*args, &block)
520
+ test_case_initialize(*args, &block)
521
+ @testcase.instance_eval do
522
+ alias :test_case_specify :specify
523
+
524
+ def specify(specname, &block)
525
+ test_case_specify(specname) { @_result.add_disabled(specname) }
526
+ end
527
+ alias :it :specify
528
+ end
529
+ end
530
+ end
531
+
532
+ class Test::Spec::Disabled < Test::Unit::Failure # :nodoc:
533
+ def initialize(name)
534
+ @name = name
535
+ end
536
+
537
+ def single_character_display
538
+ "D"
539
+ end
540
+
541
+ def short_display
542
+ @name
543
+ end
544
+
545
+ def long_display
546
+ @name + " is disabled"
547
+ end
548
+ end
549
+
550
+ class Test::Spec::Empty < Test::Unit::Failure # :nodoc:
551
+ def initialize(name)
552
+ @name = name
553
+ end
554
+
555
+ def single_character_display
556
+ ""
557
+ end
558
+
559
+ def short_display
560
+ @name
561
+ end
562
+
563
+ def long_display
564
+ @name + " is empty"
565
+ end
566
+ end
567
+
568
+
569
+ # Monkey-patch test/unit to run tests in an optionally specified order.
570
+ module Test::Unit # :nodoc:
571
+ class TestSuite # :nodoc:
572
+ undef run
573
+ def run(result, &progress_block)
574
+ sort!
575
+ yield(STARTED, name)
576
+ @tests.first.before_all if @tests.first.respond_to? :before_all
577
+ @tests.each do |test|
578
+ test.run(result, &progress_block)
579
+ end
580
+ @tests.last.after_all if @tests.last.respond_to? :after_all
581
+ yield(FINISHED, name)
582
+ end
583
+
584
+ def sort!
585
+ @tests = @tests.sort_by { |test|
586
+ test.respond_to?(:position) ? test.position : 0
587
+ }
588
+ end
589
+
590
+ def position
591
+ @tests.first.respond_to?(:position) ? @tests.first.position : 0
592
+ end
593
+ end
594
+
595
+ class TestResult # :nodoc:
596
+ # Records a disabled test.
597
+ def add_disabled(name)
598
+ notify_listeners(FAULT, Test::Spec::Disabled.new(name))
599
+ notify_listeners(CHANGED, self)
600
+ end
601
+ end
602
+ end
603
+
604
+
605
+ # Hide Test::Spec interna in backtraces.
606
+ module Test::Unit::Util::BacktraceFilter # :nodoc:
607
+ TESTSPEC_PREFIX = __FILE__.gsub(/spec\.rb\Z/, '')
608
+
609
+ # Vendor plugins like to be loaded several times, don't recurse
610
+ # infinitely then.
611
+ unless method_defined? "testspec_filter_backtrace"
612
+ alias :testspec_filter_backtrace :filter_backtrace
613
+ end
614
+
615
+ def filter_backtrace(backtrace, prefix=nil)
616
+ if prefix.nil?
617
+ testspec_filter_backtrace(testspec_filter_backtrace(backtrace),
618
+ TESTSPEC_PREFIX)
619
+ else
620
+ testspec_filter_backtrace(backtrace, prefix)
621
+ end
622
+ end
623
+ end
624
+
625
+
626
+ #-- Global helpers
627
+
628
+ class Object
629
+ def should(*args)
630
+ case args.size
631
+ when 0
632
+ Test::Spec::Should.new(self)
633
+ when 1
634
+ Test::Spec::Should.new(self).pass(args.first)
635
+ else
636
+ raise ArgumentError, "Object#should takes zero or one argument(s)."
637
+ end
638
+ end
639
+ end
640
+
641
+ module Kernel
642
+ def context(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) # :doc:
643
+ (Test::Spec::CONTEXTS[name] ||= klass.new(name, nil, superclass)).add(&block)
644
+ end
645
+
646
+ def xcontext(name, superclass=Test::Unit::TestCase, &block) # :doc:
647
+ context(name, superclass, Test::Spec::DisabledTestCase, &block)
648
+ end
649
+
650
+ def shared_context(name, &block)
651
+ Test::Spec::SHARED_CONTEXTS[name] << block
652
+ end
653
+
654
+ alias :describe :context
655
+ alias :xdescribe :xcontext
656
+ alias :describe_shared :shared_context
657
+
658
+ private :context, :xcontext, :shared_context
659
+ private :describe, :xdescribe, :describe_shared
660
+ end