relevance-test-spec 0.4.0.5

Sign up to get free protection for your applications and to get access to all the features.
data/TODO ADDED
@@ -0,0 +1,3 @@
1
+ - see ROADMAP
2
+ - better handling of .should outside of specify(?)
3
+ - shared behaviors?
data/bin/specrb ADDED
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- ruby -*-
3
+
4
+ require 'optparse'
5
+
6
+ testrbargv = []
7
+ automatic = false
8
+
9
+ opts = OptionParser.new("", 24, ' ') { |opts|
10
+ opts.banner = "Usage: specrb [options] [files | -a] [-- untouched arguments]"
11
+
12
+ opts.separator ""
13
+ opts.separator "Ruby options:"
14
+
15
+ lineno = 1
16
+ opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
17
+ eval line, TOPLEVEL_BINDING, "-e", lineno
18
+ lineno += 1
19
+ }
20
+
21
+ opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
22
+ $DEBUG = true
23
+ }
24
+ opts.on("-w", "--warn", "turn warnings on for your script") {
25
+ $-w = true
26
+ }
27
+
28
+ opts.on("-I", "--include PATH",
29
+ "specify $LOAD_PATH (may be used more than once)") { |path|
30
+ $LOAD_PATH.unshift(*path.split(":"))
31
+ }
32
+
33
+ opts.on("-r", "--require LIBRARY",
34
+ "require the library, before executing your script") { |library|
35
+ require library
36
+ }
37
+
38
+ opts.separator ""
39
+ opts.separator "test/spec options:"
40
+
41
+ opts.on("-s", "--specdox", "do AgileDox-like output") {
42
+ testrbargv << "--runner=specdox"
43
+ }
44
+ opts.on("--rdox", "do AgileDox-like output with RDoc formatting") {
45
+ testrbargv << "--runner=rdox"
46
+ }
47
+
48
+ opts.on("-a", "--automatic", "gather tests from ./test/, include ./lib/") {
49
+ $LOAD_PATH.unshift "lib" if File.directory? "lib"
50
+ automatic = true
51
+ }
52
+
53
+ opts.separator ""
54
+ opts.separator "test/unit options:"
55
+
56
+ opts.on('-n', '--name NAME', String,
57
+ "runs tests matching regexp NAME") { |n|
58
+ testrbargv << "-n" << "/#{n}/"
59
+ }
60
+
61
+ opts.on('-t', '--testcase TESTCASE', String,
62
+ "runs tests in TestCases matching regexp TESTCASE") { |t|
63
+ testrbargv << "-t" << "/#{t}/"
64
+ }
65
+
66
+ opts.separator ""
67
+ opts.separator "Common options:"
68
+
69
+ opts.on_tail("-h", "--help", "Show this message") do
70
+ puts opts
71
+ exit
72
+ end
73
+
74
+ opts.on_tail("--version", "Show version") do
75
+ require 'test/spec'
76
+ puts "specrb #{Test::Spec::VERSION}"
77
+ exit
78
+ end
79
+
80
+ opts.parse! ARGV
81
+ }
82
+
83
+ files = ARGV
84
+
85
+ if automatic
86
+ files.concat Dir["test/test_*.rb"]
87
+ files.concat Dir["test/spec_*.rb"]
88
+ files.concat Dir["spec/spec_*.rb"]
89
+ end
90
+
91
+ if files.empty?
92
+ puts opts.banner
93
+ exit 1
94
+ end
95
+
96
+ argv = testrbargv + files
97
+ # Should use -- to separate them *but* there's a bug in
98
+ # Test::Unit::AutoRunner#process_args: arguments after -- are ignored.
99
+ # (You could also argue that it's a bug in optparse.rb).
100
+
101
+ require 'test/spec'
102
+
103
+ Test::Unit.run = false
104
+ runner = Test::Unit::AutoRunner.new true
105
+ runner.process_args(argv) ||
106
+ abort("internal error calling Test::Unit, please report a bug")
107
+ exit runner.run
data/examples/stack.rb ADDED
@@ -0,0 +1,38 @@
1
+ # Copied without code changes from RSpec.
2
+
3
+ class StackUnderflowError < RuntimeError
4
+ end
5
+
6
+ class StackOverflowError < RuntimeError
7
+ end
8
+
9
+ class Stack
10
+
11
+ def initialize
12
+ @items = []
13
+ end
14
+
15
+ def push object
16
+ raise StackOverflowError if @items.length == 10
17
+ @items.push object
18
+ end
19
+
20
+ def pop
21
+ raise StackUnderflowError if @items.empty?
22
+ @items.delete @items.last
23
+ end
24
+
25
+ def peek
26
+ raise StackUnderflowError if @items.empty?
27
+ @items.last
28
+ end
29
+
30
+ def empty?
31
+ @items.empty?
32
+ end
33
+
34
+ def full?
35
+ @items.length == 10
36
+ end
37
+
38
+ end
@@ -0,0 +1,119 @@
1
+ # Copied with minor code changes (should_xxx -> should.xxx) from RSpec.
2
+
3
+ require File.dirname(__FILE__) + '/../lib/test/spec'
4
+ require File.dirname(__FILE__) + "/stack"
5
+
6
+ context "A stack (in general)" do
7
+ setup do
8
+ @stack = Stack.new
9
+ ["a","b","c"].each { |x| @stack.push x }
10
+ end
11
+
12
+ specify "should add to the top when sent 'push'" do
13
+ @stack.push "d"
14
+ @stack.peek.should.equal "d"
15
+ end
16
+
17
+ specify "should return the top item when sent 'peek'" do
18
+ @stack.peek.should.equal "c"
19
+ end
20
+
21
+ specify "should NOT remove the top item when sent 'peek'" do
22
+ @stack.peek.should.equal "c"
23
+ @stack.peek.should.equal "c"
24
+ end
25
+
26
+ specify "should return the top item when sent 'pop'" do
27
+ @stack.pop.should.equal "c"
28
+ end
29
+
30
+ specify "should remove the top item when sent 'pop'" do
31
+ @stack.pop.should.equal "c"
32
+ @stack.pop.should.equal "b"
33
+ end
34
+ end
35
+
36
+ context "An empty stack" do
37
+ setup do
38
+ @stack = Stack.new
39
+ end
40
+
41
+ specify "should be empty" do
42
+ @stack.should.be.empty
43
+ end
44
+
45
+ specify "should no longer be empty after 'push'" do
46
+ @stack.push "anything"
47
+ @stack.should.not.be.empty
48
+ end
49
+
50
+ specify "should complain when sent 'peek'" do
51
+ lambda { @stack.peek }.should.raise StackUnderflowError
52
+ end
53
+
54
+ specify "should complain when sent 'pop'" do
55
+ lambda { @stack.pop }.should.raise StackUnderflowError
56
+ end
57
+ end
58
+
59
+ context "An almost empty stack (with one item)" do
60
+ setup do
61
+ @stack = Stack.new
62
+ @stack.push 3
63
+ end
64
+
65
+ specify "should not be empty" do
66
+ @stack.should.not.be.empty
67
+ end
68
+
69
+ specify "should remain not empty after 'peek'" do
70
+ @stack.peek
71
+ @stack.should.not.be.empty
72
+ end
73
+
74
+ specify "should become empty after 'pop'" do
75
+ @stack.pop
76
+ @stack.should.be.empty
77
+ end
78
+ end
79
+
80
+ context "An almost full stack (with one item less than capacity)" do
81
+ setup do
82
+ @stack = Stack.new
83
+ (1..9).each { |i| @stack.push i }
84
+ end
85
+
86
+ specify "should not be full" do
87
+ @stack.should.not.be.full
88
+ end
89
+
90
+ specify "should become full when sent 'push'" do
91
+ @stack.push Object.new
92
+ @stack.should.be.full
93
+ end
94
+ end
95
+
96
+ context "A full stack" do
97
+ setup do
98
+ @stack = Stack.new
99
+ (1..10).each { |i| @stack.push i }
100
+ end
101
+
102
+ specify "should be full" do
103
+ @stack.should.be.full
104
+ end
105
+
106
+ specify "should remain full after 'peek'" do
107
+ @stack.peek
108
+ @stack.should.be.full
109
+ end
110
+
111
+ specify "should no longer be full after 'pop'" do
112
+ @stack.pop
113
+ @stack.should.not.be.full
114
+ end
115
+
116
+ specify "should complain on 'push'" do
117
+ lambda { @stack.push Object.new }.should.raise StackOverflowError
118
+ end
119
+ end
data/lib/test/spec.rb ADDED
@@ -0,0 +1,731 @@
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
+ require 'test/unit/collector'
11
+ require 'test/unit/collector/objectspace'
12
+ require 'test/spec/focused/collector-extensions'
13
+
14
+ class Test::Unit::AutoRunner # :nodoc:
15
+ RUNNERS[:specdox] = lambda {
16
+ require 'test/spec/dox'
17
+ Test::Unit::UI::SpecDox::TestRunner
18
+ }
19
+
20
+ RUNNERS[:rdox] = lambda {
21
+ require 'test/spec/rdox'
22
+ Test::Unit::UI::RDox::TestRunner
23
+ }
24
+ end
25
+
26
+ module Test # :nodoc:
27
+ end
28
+
29
+ module Test::Spec
30
+ require 'test/spec/version'
31
+ require 'test/spec/focused/focused'
32
+ require 'test/spec/rails_helper'
33
+
34
+ CONTEXTS = {} # :nodoc:
35
+ SHARED_CONTEXTS = Hash.new { |h,k| h[k] = [] } # :nodoc:
36
+ include Test::Spec::Focused
37
+
38
+ class DefinitionError < StandardError
39
+ end
40
+
41
+ class Should
42
+ include Test::Unit::Assertions
43
+
44
+ def self.deprecated_alias(to, from) # :nodoc:
45
+ define_method(to) { |*args|
46
+ warn "Test::Spec::Should##{to} is deprecated and will be removed in future versions."
47
+ __send__ from, *args
48
+ }
49
+ end
50
+
51
+ def initialize(object, message=nil)
52
+ @object = object
53
+ @message = message
54
+ end
55
+
56
+ $TEST_SPEC_TESTCASE = nil
57
+ def add_assertion
58
+ $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
59
+ end
60
+
61
+
62
+ def an
63
+ self
64
+ end
65
+
66
+ def a
67
+ self
68
+ end
69
+
70
+ def not(*args)
71
+ case args.size
72
+ when 0
73
+ ShouldNot.new(@object, @message)
74
+ when 1
75
+ ShouldNot.new(@object, @message).pass(args.first)
76
+ else
77
+ raise ArgumentError, "#not takes zero or one argument(s)."
78
+ end
79
+ end
80
+
81
+ def messaging(message)
82
+ @message = message.to_s
83
+ self
84
+ end
85
+ alias blaming messaging
86
+
87
+ def satisfy(&block)
88
+ assert_block(@message || "satisfy block failed.") {
89
+ yield @object
90
+ }
91
+ end
92
+
93
+ def equal(value)
94
+ assert_equal value, @object, @message
95
+ end
96
+ alias == equal
97
+
98
+ def close(value, delta)
99
+ assert_in_delta value, @object, delta, @message
100
+ end
101
+ deprecated_alias :be_close, :close
102
+
103
+ def be(*value)
104
+ case value.size
105
+ when 0
106
+ self
107
+ when 1
108
+ if CustomShould === value.first
109
+ pass value.first
110
+ else
111
+ assert_same value.first, @object, @message
112
+ end
113
+ else
114
+ raise ArgumentError, "should.be needs zero or one argument"
115
+ end
116
+ end
117
+
118
+ def match(value)
119
+ assert_match value, @object, @message
120
+ end
121
+ alias =~ match
122
+
123
+ def instance_of(klass)
124
+ assert_instance_of klass, @object, @message
125
+ end
126
+ deprecated_alias :be_an_instance_of, :instance_of
127
+
128
+ def kind_of(klass)
129
+ assert_kind_of klass, @object, @message
130
+ end
131
+ deprecated_alias :be_a_kind_of, :kind_of
132
+
133
+ def respond_to(method)
134
+ assert_respond_to @object, method, @message
135
+ end
136
+
137
+ def _raise(*args, &block)
138
+ args = [RuntimeError] if args.empty?
139
+ block ||= @object
140
+ assert_raise(*(args + [@message]), &block)
141
+ end
142
+
143
+ def throw(*args)
144
+ assert_throws(*(args + [@message]), &@object)
145
+ end
146
+
147
+ def nil
148
+ assert_nil @object, @message
149
+ end
150
+ deprecated_alias :be_nil, :nil
151
+
152
+
153
+ def include(value)
154
+ msg = build_message(@message, "<?> expected to include ?, but it didn't.",
155
+ @object, value)
156
+ assert_block(msg) { @object.include?(value) }
157
+ end
158
+
159
+ def >(value)
160
+ assert_operator @object, :>, value, @message
161
+ end
162
+
163
+ def >=(value)
164
+ assert_operator @object, :>=, value, @message
165
+ end
166
+
167
+ def <(value)
168
+ assert_operator @object, :<, value, @message
169
+ end
170
+
171
+ def <=(value)
172
+ assert_operator @object, :<=, value, @message
173
+ end
174
+
175
+ def ===(value)
176
+ assert_operator @object, :===, value, @message
177
+ end
178
+
179
+ def pass(custom)
180
+ _wrap_assertion {
181
+ assert_nothing_raised(Test::Unit::AssertionFailedError,
182
+ @message || custom.failure_message) {
183
+ assert custom.matches?(@object), @message || custom.failure_message
184
+ }
185
+ }
186
+ end
187
+
188
+ def method_missing(name, *args, &block)
189
+ # This will make raise call Kernel.raise, and self.raise call _raise.
190
+ return _raise(*args, &block) if name == :raise
191
+
192
+ if @object.respond_to?("#{name}?")
193
+ assert @object.__send__("#{name}?", *args),
194
+ "#{name}? expected to be true. #{@message}"
195
+ else
196
+ if @object.respond_to?(name)
197
+ assert @object.__send__(name, *args),
198
+ "#{name} expected to be true. #{@message}"
199
+ else
200
+ super
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ class ShouldNot
207
+ include Test::Unit::Assertions
208
+
209
+ def initialize(object, message=nil)
210
+ @object = object
211
+ @message = message
212
+ end
213
+
214
+ def add_assertion
215
+ $TEST_SPEC_TESTCASE && $TEST_SPEC_TESTCASE.__send__(:add_assertion)
216
+ end
217
+
218
+
219
+ def satisfy(&block)
220
+ assert_block(@message || "not.satisfy block succeded.") {
221
+ not yield @object
222
+ }
223
+ end
224
+
225
+ def equal(value)
226
+ assert_not_equal value, @object, @message
227
+ end
228
+ alias == equal
229
+
230
+ def be(*value)
231
+ case value.size
232
+ when 0
233
+ self
234
+ when 1
235
+ if CustomShould === value.first
236
+ pass value.first
237
+ else
238
+ assert_not_same value.first, @object, @message
239
+ end
240
+ else
241
+ Kernel.raise ArgumentError, "should.be needs zero or one argument"
242
+ end
243
+ end
244
+
245
+ def match(value)
246
+ # Icky Regexp check
247
+ assert_no_match value, @object, @message
248
+ end
249
+ alias =~ match
250
+
251
+ def _raise(*args, &block)
252
+ block ||= @object
253
+ assert_nothing_raised(*(args+[@message]), &block)
254
+ end
255
+
256
+ def throw
257
+ assert_nothing_thrown(@message, &@object)
258
+ end
259
+
260
+ def nil
261
+ assert_not_nil @object, @message
262
+ end
263
+
264
+ def be_nil
265
+ warn "Test::Spec::ShouldNot#be_nil is deprecated and will be removed in future versions."
266
+ self.nil
267
+ end
268
+
269
+ def not(*args)
270
+ case args.size
271
+ when 0
272
+ Should.new(@object, @message)
273
+ when 1
274
+ Should.new(@object, @message).pass(args.first)
275
+ else
276
+ raise ArgumentError, "#not takes zero or one argument(s)."
277
+ end
278
+ end
279
+
280
+ def pass(custom)
281
+ _wrap_assertion {
282
+ begin
283
+ assert !custom.matches?(@object), @message || custom.failure_message
284
+ end
285
+ }
286
+ end
287
+
288
+ def method_missing(name, *args, &block)
289
+ # This will make raise call Kernel.raise, and self.raise call _raise.
290
+ return _raise(*args, &block) if name == :raise
291
+
292
+ if @object.respond_to?("#{name}?")
293
+ assert_block("#{name}? expected to be false. #{@message}") {
294
+ not @object.__send__("#{name}?", *args)
295
+ }
296
+ else
297
+ if @object.respond_to?(name)
298
+ assert_block("#{name} expected to be false. #{@message}") {
299
+ not @object.__send__("#{name}", *args)
300
+ }
301
+ else
302
+ super
303
+ end
304
+ end
305
+ end
306
+
307
+ end
308
+
309
+ class CustomShould
310
+ attr_accessor :object
311
+
312
+ def initialize(obj)
313
+ self.object = obj
314
+ end
315
+
316
+ def failure_message
317
+ "#{self.class.name} failed"
318
+ end
319
+
320
+ def matches?(*args, &block)
321
+ assumptions(*args, &block)
322
+ true
323
+ end
324
+
325
+ def assumptions(*args, &block)
326
+ raise NotImplementedError, "you need to supply a #{self.class}#matches? method"
327
+ end
328
+ end
329
+ end
330
+
331
+ class Test::Spec::TestCase
332
+ attr_reader :testcase
333
+ attr_reader :name
334
+ attr_reader :position
335
+ attr_accessor :ignore
336
+
337
+ module InstanceMethods
338
+ def setup # :nodoc:
339
+ $TEST_SPEC_TESTCASE = self
340
+ super
341
+ self.class.setups.each { |s| instance_eval(&s) }
342
+ end
343
+
344
+ def teardown # :nodoc:
345
+ super
346
+ self.class.teardowns.each { |t| instance_eval(&t) }
347
+ end
348
+
349
+ def before_all
350
+ self.class.before_all.each { |t| instance_eval(&t) }
351
+ end
352
+
353
+ def after_all
354
+ self.class.after_all.each { |t| instance_eval(&t) }
355
+ end
356
+
357
+ def initialize(name)
358
+ super name
359
+
360
+ # Don't let the default_test clutter up the results and don't
361
+ # flunk if no tests given, either.
362
+ throw :invalid_test if name.to_s == "default_test"
363
+ end
364
+
365
+ def position
366
+ self.class.position
367
+ end
368
+
369
+ def context(*args)
370
+ raise Test::Spec::DefinitionError, "context definition is not allowed inside a specify-block"
371
+ end
372
+
373
+ alias :describe :context
374
+ end
375
+
376
+ module ClassMethods
377
+ attr_accessor :count
378
+ attr_accessor :name
379
+ attr_accessor :position
380
+ attr_accessor :parent
381
+
382
+ attr_accessor :setups
383
+ attr_accessor :teardowns
384
+
385
+ attr_accessor :before_all
386
+ attr_accessor :after_all
387
+
388
+ # old-style (RSpec <1.0):
389
+
390
+ def context(name_or_class, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block)
391
+ cls_string = name_or_class.is_a?(String) ? name_or_class : name_or_class.class.to_s
392
+ superclass = Test::Spec::RailsHelper.figure_out_superclass_from_name(name_or_class, superclass)
393
+
394
+ superclass = self.superclass
395
+
396
+ if self.respond_to?(:controller_class=)
397
+ controller_klass = name.is_a?(Class) ? name : Test::Spec::RailsHelper::infer_controller_class(name)
398
+ self.controller_class = controller_klass if controller_klass
399
+ end
400
+
401
+ (Test::Spec::CONTEXTS[self.name.to_s + "\t" + cls_string] ||= klass.new(cls_string, self, superclass)).add(&block)
402
+ end
403
+
404
+ def fcontext(name, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block)
405
+ Test::Spec.set_focused_mode(true)
406
+ context(name, superclass, Test::Spec::FocusedTestCase, &block)
407
+ end
408
+
409
+ def xcontext(name, superclass=Test::Unit::TestCase, &block)
410
+ context(name, superclass, Test::Spec::DisabledTestCase, &block)
411
+ end
412
+
413
+ def specify(specname, &block)
414
+ if block.nil?
415
+ pspecify(specname)
416
+ else
417
+ self.count += 1 # Let them run in order of definition
418
+ define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block) unless Test::Spec.focused_mode?
419
+ end
420
+ end
421
+
422
+ def undef_previous_specs
423
+ instance_methods.grep(/test_spec/).each do |meth|
424
+ undef_method meth
425
+ end
426
+ end
427
+
428
+ def fspecify(specname, &block)
429
+ Test::Spec.set_focused_mode(true, self.name)
430
+ undef_previous_specs
431
+ self.count += 1 # Let them run in order of definition
432
+ define_method("test_spec {%s} %03d [%s]" % [name, count, specname], &block)
433
+ end
434
+
435
+ def xspecify(specname, &block)
436
+ specify specname do
437
+ @_result.add_disabled(specname)
438
+ end
439
+ end
440
+
441
+ def pspecify(specname, &block)
442
+ specify specname do
443
+ @_result.add_pending(specname)
444
+ end
445
+ end
446
+
447
+ def setup(&block)
448
+ setups << block
449
+ end
450
+
451
+ def teardown(&block)
452
+ teardowns << block
453
+ end
454
+
455
+ def shared_context(name, &block)
456
+ Test::Spec::SHARED_CONTEXTS[self.name + "\t" + name] << block
457
+ end
458
+
459
+ def behaves_like(shared_context)
460
+ if Test::Spec::SHARED_CONTEXTS.include?(shared_context)
461
+ Test::Spec::SHARED_CONTEXTS[shared_context].each { |block|
462
+ instance_eval(&block)
463
+ }
464
+ elsif Test::Spec::SHARED_CONTEXTS.include?(self.name + "\t" + shared_context)
465
+ Test::Spec::SHARED_CONTEXTS[self.name + "\t" + shared_context].each { |block|
466
+ instance_eval(&block)
467
+ }
468
+ else
469
+ raise NameError, "Shared context #{shared_context} not found."
470
+ end
471
+ end
472
+ alias :it_should_behave_like :behaves_like
473
+
474
+ # new-style (RSpec 1.0+):
475
+
476
+ alias :describe :context
477
+ alias :fdescribe :fcontext
478
+ alias :describe_shared :shared_context
479
+ alias :it :specify
480
+ alias :they :specify
481
+ alias :xit :xspecify
482
+ alias :fit :fspecify
483
+ alias :pit :pspecify
484
+
485
+ def before(kind=:each, &block)
486
+ case kind
487
+ when :each
488
+ setup(&block)
489
+ when :all
490
+ before_all << block
491
+ else
492
+ raise ArgumentError, "invalid argument: before(#{kind.inspect})"
493
+ end
494
+ end
495
+
496
+ def after(kind=:each, &block)
497
+ case kind
498
+ when :each
499
+ teardown(&block)
500
+ when :all
501
+ after_all << block
502
+ else
503
+ raise ArgumentError, "invalid argument: after(#{kind.inspect})"
504
+ end
505
+ end
506
+
507
+
508
+ def init(name, position, parent)
509
+ self.position = position
510
+ self.parent = parent
511
+
512
+ if parent
513
+ self.name = parent.name.to_s + "\t" + name
514
+ else
515
+ self.name = name.to_s
516
+ end
517
+
518
+ self.count = 0
519
+ self.setups = []
520
+ self.teardowns = []
521
+
522
+ self.before_all = []
523
+ self.after_all = []
524
+ end
525
+ end
526
+
527
+ @@POSITION = 0
528
+
529
+ def initialize(name, parent=nil, superclass=Test::Unit::TestCase)
530
+ @testcase = Class.new(superclass) {
531
+ include Test::Spec::TestCase::InstanceMethods
532
+ extend Test::Spec::TestCase::ClassMethods
533
+ # p "extending onto #{self} with class #{self.class} with superclass #{superclass} and ancestors #{self.ancestors.join(",")}"
534
+ }
535
+
536
+ @@POSITION ||= 0
537
+ @@POSITION = @@POSITION + 1
538
+ @testcase.init(name, @@POSITION, parent)
539
+ end
540
+
541
+ def add(&block)
542
+ raise ArgumentError, "context needs a block" if block.nil?
543
+
544
+ @testcase.class_eval(&block)
545
+ self
546
+ end
547
+
548
+ def ignore?
549
+ @ignore == true
550
+ end
551
+
552
+ end
553
+
554
+ class Test::Spec::FocusedTestCase < Test::Spec::TestCase
555
+
556
+ def initialize(name, parent=nil, superclass=Test::Unit::TestCase)
557
+ super
558
+ end
559
+
560
+ def long_display
561
+ @name + " is in focused mode"
562
+ end
563
+
564
+ end
565
+
566
+ (Test::Spec::DisabledTestCase = Test::Spec::TestCase.dup).class_eval do
567
+ alias :test_case_initialize :initialize
568
+
569
+ def initialize(*args, &block)
570
+ test_case_initialize(*args, &block)
571
+ @testcase.instance_eval do
572
+ alias :test_case_specify :specify
573
+
574
+ def specify(specname, &block)
575
+ test_case_specify(specname) { @_result.add_disabled(specname) }
576
+ end
577
+ alias :it :specify
578
+
579
+ end
580
+ end
581
+ end
582
+
583
+ class Test::Spec::Failure < Test::Unit::Failure # :nodoc:
584
+ attr_reader :single_character_display
585
+
586
+ def initialize(attrs)
587
+ @name = attrs[:name]
588
+ @single_character_display = attrs[:single_character_display]
589
+ @long_display = attrs[:long_display]
590
+ end
591
+
592
+ def short_display
593
+ @name
594
+ end
595
+
596
+ def long_display
597
+ @long_display % @name
598
+ end
599
+ end
600
+
601
+ class Test::Spec::Disabled < Test::Spec::Failure # :nodoc:
602
+ def initialize(name)
603
+ super(:name => name, :single_character_display => 'D', :long_display => "Disabled: %s")
604
+ end
605
+ end
606
+
607
+ class Test::Spec::Empty < Test::Spec::Failure # :nodoc:
608
+ def initialize(name)
609
+ super(:name => name, :single_character_display => "", :long_display => "Empty: %s")
610
+ end
611
+ end
612
+
613
+ class Test::Spec::Pending < Test::Spec::Failure # :nodoc:
614
+ def initialize(name)
615
+ super(:name => name, :single_character_display => 'P', :long_display => "Pending: %s")
616
+ end
617
+ end
618
+
619
+ # Monkey-patch test/unit to run tests in an optionally specified order.
620
+ module Test::Unit # :nodoc:
621
+ class TestSuite # :nodoc:
622
+ undef run
623
+
624
+ def run(result, &progress_block)
625
+ sort!
626
+
627
+ yield(STARTED, name)
628
+
629
+ @tests.first.before_all if @tests.first.respond_to? :before_all
630
+ @tests.each do |test|
631
+ test.run(result, &progress_block)
632
+ end
633
+ @tests.last.after_all if @tests.last.respond_to? :after_all
634
+ yield(FINISHED, name)
635
+ end
636
+
637
+ def sort!
638
+ @tests = @tests.sort_by { |test|
639
+ test.respond_to?(:position) ? test.position : 0
640
+ }
641
+ end
642
+
643
+ def position
644
+ @tests.first.respond_to?(:position) ? @tests.first.position : 0
645
+ end
646
+ end
647
+
648
+ class TestResult # :nodoc:
649
+ # Records a disabled test.
650
+ def add_disabled(name)
651
+ notify_listeners(FAULT, Test::Spec::Disabled.new(name))
652
+ notify_listeners(CHANGED, self)
653
+ end
654
+
655
+ def add_pending(name)
656
+ notify_listeners(FAULT, Test::Spec::Pending.new(name))
657
+ notify_listeners(CHANGED, self)
658
+ end
659
+ end
660
+ end
661
+
662
+
663
+ # Hide Test::Spec interna in backtraces.
664
+ module Test::Unit::Util::BacktraceFilter # :nodoc:
665
+ TESTSPEC_PREFIX = __FILE__.gsub(/spec\.rb\Z/, '')
666
+
667
+ # Vendor plugins like to be loaded several times, don't recurse
668
+ # infinitely then.
669
+ unless method_defined? "testspec_filter_backtrace"
670
+ alias :testspec_filter_backtrace :filter_backtrace
671
+ end
672
+
673
+ def filter_backtrace(backtrace, prefix=nil)
674
+ if prefix.nil?
675
+ testspec_filter_backtrace(testspec_filter_backtrace(backtrace),
676
+ TESTSPEC_PREFIX)
677
+ else
678
+ testspec_filter_backtrace(backtrace, prefix)
679
+ end
680
+ end
681
+ end
682
+
683
+
684
+ #-- Global helpers
685
+
686
+ class Object
687
+ def should(*args)
688
+ case args.size
689
+ when 0
690
+ Test::Spec::Should.new(self)
691
+ when 1
692
+ Test::Spec::Should.new(self).pass(args.first)
693
+ else
694
+ raise ArgumentError, "Object#should takes zero or one argument(s)."
695
+ end
696
+ end
697
+ end
698
+
699
+ module Kernel
700
+ def context(name_or_class, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) # :doc:
701
+ superclass = Test::Spec::RailsHelper.figure_out_superclass_from_name(name_or_class, superclass)
702
+
703
+ if superclass.respond_to?(:controller_class=)
704
+ controller_klass = name_or_class.is_a?(Class) ? name_or_class : Test::Spec::RailsHelper::infer_controller_class(name_or_class)
705
+ superclass.controller_class = controller_klass if controller_klass
706
+ end
707
+
708
+ (Test::Spec::CONTEXTS[name_or_class] ||= klass.new(name_or_class, nil, superclass)).add(&block)
709
+ end
710
+
711
+ def fcontext(name_or_class, superclass=Test::Unit::TestCase, klass=Test::Spec::TestCase, &block) # :doc:
712
+ Test::Spec.set_focused_mode(true)
713
+ context(name_or_class, superclass, Test::Spec::FocusedTestCase, &block)
714
+ end
715
+
716
+ def xcontext(name_or_class, superclass=Test::Unit::TestCase, &block) # :doc:
717
+ context(name_or_class, superclass, Test::Spec::DisabledTestCase, &block)
718
+ end
719
+
720
+ def shared_context(name, &block)
721
+ Test::Spec::SHARED_CONTEXTS[name] << block
722
+ end
723
+
724
+ alias :describe :context
725
+ alias :xdescribe :xcontext
726
+ alias :describe_shared :shared_context
727
+
728
+ private :context, :xcontext, :shared_context
729
+ private :describe, :xdescribe, :describe_shared
730
+
731
+ end