relevance-test-spec 0.4.0.5

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