nullstyle-test-spec 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +18 -0
- data/README +376 -0
- data/Rakefile +165 -0
- data/lib/test/spec.rb +660 -0
- data/lib/test/spec/dox.rb +148 -0
- data/lib/test/spec/rdox.rb +25 -0
- data/lib/test/spec/should-output.rb +49 -0
- data/lib/test/spec/version.rb +8 -0
- data/test-spec.gemspec +55 -0
- data/test/spec_dox.rb +39 -0
- data/test/spec_flexmock.rb +214 -0
- data/test/spec_mocha.rb +118 -0
- data/test/spec_nestedcontexts.rb +26 -0
- data/test/spec_new_style.rb +80 -0
- data/test/spec_should-output.rb +26 -0
- data/test/spec_testspec.rb +700 -0
- data/test/spec_testspec_order.rb +26 -0
- data/test/test_testunit.rb +22 -0
- metadata +80 -0
@@ -0,0 +1,148 @@
|
|
1
|
+
require 'test/unit/ui/console/testrunner'
|
2
|
+
|
3
|
+
module Test::Unit::UI # :nodoc:
|
4
|
+
module SpecDox # :nodoc:
|
5
|
+
class TestRunner < Test::Unit::UI::Console::TestRunner
|
6
|
+
protected
|
7
|
+
def setup_mediator
|
8
|
+
@mediator = create_mediator(@suite)
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_fault(fault)
|
12
|
+
if fault.kind_of? Test::Spec::Disabled
|
13
|
+
@disabled += 1
|
14
|
+
output_no_nl " (disabled)"
|
15
|
+
elsif fault.kind_of? Test::Spec::Empty
|
16
|
+
@empty += 1
|
17
|
+
output_no_nl " (empty)"
|
18
|
+
else
|
19
|
+
@faults << fault
|
20
|
+
word = fault.class.name[/(.*::)?(.*)/, 2].upcase
|
21
|
+
output_no_nl " (#{word} - #{@faults.size})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def started(result)
|
26
|
+
@result = result
|
27
|
+
@context = nil
|
28
|
+
@contexts = []
|
29
|
+
@disabled = 0
|
30
|
+
@empty = 0
|
31
|
+
indent 0
|
32
|
+
end
|
33
|
+
|
34
|
+
def finished(elapsed_time)
|
35
|
+
nl
|
36
|
+
output "Finished in #{elapsed_time} seconds."
|
37
|
+
@faults.each_with_index do |fault, index|
|
38
|
+
nl
|
39
|
+
output("%3d) %s" % [index + 1, fault.long_display])
|
40
|
+
end
|
41
|
+
nl
|
42
|
+
output_result
|
43
|
+
end
|
44
|
+
|
45
|
+
def output_result
|
46
|
+
if @disabled > 0
|
47
|
+
disabled = ", #{@disabled} disabled"
|
48
|
+
else
|
49
|
+
disabled = ""
|
50
|
+
end
|
51
|
+
|
52
|
+
if @empty > 0
|
53
|
+
empty = ", #{@empty} empty"
|
54
|
+
else
|
55
|
+
empty = ""
|
56
|
+
end
|
57
|
+
|
58
|
+
r = ("%d specifications#{disabled}#{empty} " +
|
59
|
+
"(%d requirements), %d failures") % [
|
60
|
+
@result.run_count, @result.assertion_count, @result.failure_count]
|
61
|
+
r << ", #{@result.error_count} errors" if @result.error_count > 0
|
62
|
+
output r
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_started(name)
|
66
|
+
return if special_test? name
|
67
|
+
|
68
|
+
contextname, @specname = unmangle name
|
69
|
+
return if contextname.nil? || @specname.nil?
|
70
|
+
|
71
|
+
if @context != contextname
|
72
|
+
@context = contextname
|
73
|
+
|
74
|
+
@old_contexts = @contexts
|
75
|
+
@contexts = @context.split("\t")
|
76
|
+
|
77
|
+
common = 0
|
78
|
+
@contexts.zip(@old_contexts) { |a, b|
|
79
|
+
break if a != b
|
80
|
+
common += 1
|
81
|
+
}
|
82
|
+
|
83
|
+
nl if common == 0
|
84
|
+
|
85
|
+
@contexts[common..-1].each_with_index { |head, i|
|
86
|
+
indent common + i
|
87
|
+
output_heading head
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
91
|
+
@assertions = @result.assertion_count
|
92
|
+
@prevdisabled = @disabled
|
93
|
+
output_item @specname
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_finished(name)
|
97
|
+
return if special_test? name
|
98
|
+
|
99
|
+
# Did any assertion run?
|
100
|
+
if @assertions == @result.assertion_count && @prevdisabled == @disabled
|
101
|
+
add_fault Test::Spec::Empty.new(@specname)
|
102
|
+
end
|
103
|
+
|
104
|
+
# Don't let empty contexts clutter up the output.
|
105
|
+
nl unless name =~ /\Adefault_test\(/
|
106
|
+
end
|
107
|
+
|
108
|
+
def output_no_nl(something, level=NORMAL)
|
109
|
+
@io.write(something) if (output?(level))
|
110
|
+
@io.flush
|
111
|
+
end
|
112
|
+
|
113
|
+
def output_item(item)
|
114
|
+
output_no_nl "#{@prefix}- #{item}"
|
115
|
+
end
|
116
|
+
|
117
|
+
def output_heading(heading)
|
118
|
+
output "#{@prefix}#{heading}"
|
119
|
+
end
|
120
|
+
|
121
|
+
def unmangle(name)
|
122
|
+
if name =~ /\Atest_spec \{(.*?)\} \d+ \[(.*)\]/
|
123
|
+
contextname = $1
|
124
|
+
specname = $2
|
125
|
+
elsif name =~ /test_(.*?)\((.*)\)$/
|
126
|
+
specname = $1
|
127
|
+
contextname = $2
|
128
|
+
|
129
|
+
contextname.gsub!(/^Test\B|\BTest$/, '')
|
130
|
+
specname.gsub!(/_/, ' ')
|
131
|
+
else
|
132
|
+
contextname = specname = nil
|
133
|
+
end
|
134
|
+
|
135
|
+
[contextname, specname]
|
136
|
+
end
|
137
|
+
|
138
|
+
def indent(depth)
|
139
|
+
@indent = depth
|
140
|
+
@prefix = " " * depth
|
141
|
+
end
|
142
|
+
|
143
|
+
def special_test?(name)
|
144
|
+
name =~ /\Atest_spec \{.*?\} (-1 BEFORE|AFTER) ALL\(/
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'test/spec/dox'
|
2
|
+
|
3
|
+
module Test::Unit::UI # :nodoc:
|
4
|
+
module RDox # :nodoc:
|
5
|
+
class TestRunner < Test::Unit::UI::SpecDox::TestRunner
|
6
|
+
def output_heading(heading)
|
7
|
+
output "#{@headprefix} #{heading}"
|
8
|
+
end
|
9
|
+
|
10
|
+
def output_item(item)
|
11
|
+
output_no_nl "* #{item}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def finished(elapsed_time)
|
15
|
+
nl
|
16
|
+
output_result
|
17
|
+
end
|
18
|
+
|
19
|
+
def indent(depth)
|
20
|
+
@prefix = ""
|
21
|
+
@headprefix = "==" + "=" * depth
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# Code adapted from rs, written by Eero Saynatkari.
|
2
|
+
require 'fileutils'
|
3
|
+
require 'tmpdir'
|
4
|
+
|
5
|
+
class Test::Spec::Should
|
6
|
+
# Captures output from the IO given as
|
7
|
+
# the second argument (STDIN by default)
|
8
|
+
# and matches it against a String or
|
9
|
+
# Regexp given as the first argument.
|
10
|
+
def output(expected, to = STDOUT)
|
11
|
+
# Store the old stream
|
12
|
+
old_to = to.dup
|
13
|
+
|
14
|
+
# Obtain a filehandle to replace (works with Readline)
|
15
|
+
to.reopen File.open(File.join(Dir.tmpdir, "should_output_#{$$}"), "w+")
|
16
|
+
|
17
|
+
# Execute
|
18
|
+
@object.call
|
19
|
+
|
20
|
+
# Restore
|
21
|
+
out = to.dup
|
22
|
+
to.reopen old_to
|
23
|
+
|
24
|
+
# Grab the data
|
25
|
+
out.rewind
|
26
|
+
output = out.read
|
27
|
+
|
28
|
+
# Match up
|
29
|
+
case expected
|
30
|
+
when Regexp
|
31
|
+
output.should.match expected
|
32
|
+
else
|
33
|
+
output.should.equal expected
|
34
|
+
end # case expected
|
35
|
+
|
36
|
+
# Clean up
|
37
|
+
ensure
|
38
|
+
out.close
|
39
|
+
|
40
|
+
# STDIO redirection will break else
|
41
|
+
begin
|
42
|
+
to.seek 0, IO::SEEK_END
|
43
|
+
rescue Errno::ESPIPE
|
44
|
+
rescue Errno::EPIPE
|
45
|
+
end
|
46
|
+
|
47
|
+
FileUtils.rm_f out.path
|
48
|
+
end # output
|
49
|
+
end # Test::Spec::Should
|
data/test-spec.gemspec
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = "test-spec"
|
3
|
+
s.version = "0.4.1"
|
4
|
+
s.date = "2008-04-30"
|
5
|
+
s.summary = "a Behaviour Driven Development interface for Test::Unit"
|
6
|
+
s.email = "chneukirchen@gmail.com"
|
7
|
+
s.homepage = "http://test-spec.rubyforge.org"
|
8
|
+
|
9
|
+
s.description = <<EOF
|
10
|
+
test/spec layers an RSpec-inspired interface on top of Test::Unit, so
|
11
|
+
you can mix TDD and BDD (Behavior-Driven Development).
|
12
|
+
|
13
|
+
test/spec is a clean-room implementation that maps most kinds of
|
14
|
+
Test::Unit assertions to a `should'-like syntax.
|
15
|
+
EOF
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.authors = ["Christian Neukirchen"]
|
19
|
+
|
20
|
+
s.files = [
|
21
|
+
"Manifest.txt",
|
22
|
+
"README",
|
23
|
+
"Rakefile",
|
24
|
+
"test-spec.gemspec",
|
25
|
+
"lib/test/spec.rb",
|
26
|
+
"lib/test/spec/dox.rb",
|
27
|
+
"lib/test/spec/rdox.rb",
|
28
|
+
"lib/test/spec/should-output.rb",
|
29
|
+
"lib/test/spec/version.rb",
|
30
|
+
"test/spec_dox.rb",
|
31
|
+
"test/spec_flexmock.rb",
|
32
|
+
"test/spec_mocha.rb",
|
33
|
+
"test/spec_nestedcontexts.rb",
|
34
|
+
"test/spec_new_style.rb",
|
35
|
+
"test/spec_should-output.rb",
|
36
|
+
"test/spec_testspec.rb",
|
37
|
+
"test/spec_testspec_order.rb",
|
38
|
+
"test/test_testunit.rb",
|
39
|
+
]
|
40
|
+
|
41
|
+
s.test_files = [
|
42
|
+
"test/spec_dox.rb",
|
43
|
+
"test/spec_flexmock.rb",
|
44
|
+
"test/spec_mocha.rb",
|
45
|
+
"test/spec_nestedcontexts.rb",
|
46
|
+
"test/spec_new_style.rb",
|
47
|
+
"test/spec_should-output.rb",
|
48
|
+
"test/spec_testspec.rb",
|
49
|
+
"test/spec_testspec_order.rb",
|
50
|
+
"test/test_testunit.rb",
|
51
|
+
]
|
52
|
+
|
53
|
+
s.rdoc_options = ["--main", "README"]
|
54
|
+
s.extra_rdoc_files = ["Manifest.txt", "README"]
|
55
|
+
end
|
data/test/spec_dox.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'test/spec'
|
2
|
+
|
3
|
+
require 'test/spec/dox'
|
4
|
+
|
5
|
+
context "SpecDox" do
|
6
|
+
setup do
|
7
|
+
r = Test::Unit::UI::SpecDox::TestRunner.new(nil)
|
8
|
+
@unmangler = r.method(:unmangle)
|
9
|
+
end
|
10
|
+
|
11
|
+
specify "can unmangle Test::Unit names correctly" do
|
12
|
+
@unmangler["test_foo_bar(TestFoo)"].should.equal ["Foo", "foo bar"]
|
13
|
+
@unmangler["test_foo_bar(FooTest)"].should.equal ["Foo", "foo bar"]
|
14
|
+
@unmangler["test_he_he(Foo)"].should.equal ["Foo", "he he"]
|
15
|
+
@unmangler["test_heh(Foo)"].should.equal ["Foo", "heh"]
|
16
|
+
|
17
|
+
@unmangler["test_heh(Test::Unit::TC_Assertions)"].
|
18
|
+
should.equal ["Test::Unit::TC_Assertions", "heh"]
|
19
|
+
|
20
|
+
@unmangler["test_heh(Foo::Bar::Test)"].
|
21
|
+
should.equal ["Foo::Bar::Test", "heh"]
|
22
|
+
end
|
23
|
+
|
24
|
+
specify "can unmangle Test::Spec names correctly" do
|
25
|
+
@unmangler["test_spec {context} 007 [whee]()"].
|
26
|
+
should.equal ["context", "whee"]
|
27
|
+
@unmangler["test_spec {a bit longish context} 069 [and more text]()"].
|
28
|
+
should.equal ["a bit longish context", "and more text"]
|
29
|
+
@unmangler["test_spec {special chars !\"/&%$} 2 [special chars !\"/&%$]()"].
|
30
|
+
should.equal ["special chars !\"/&%$", "special chars !\"/&%$"]
|
31
|
+
@unmangler["test_spec {[]} 666666 [{}]()"].
|
32
|
+
should.equal ["[]", "{}"]
|
33
|
+
end
|
34
|
+
|
35
|
+
specify "has sensible fallbacks" do
|
36
|
+
@unmangler["weird"].should.equal [nil, nil]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,214 @@
|
|
1
|
+
# Adapted from flexmock (http://onestepback.org/software/flexmock).
|
2
|
+
#
|
3
|
+
# Copyright 2006 by Jim Weirich (jweirich@one.net).
|
4
|
+
# All rights reserved.
|
5
|
+
|
6
|
+
# Permission is granted for use, copying, modification, distribution,
|
7
|
+
# and distribution of modified versions of this work as long as the
|
8
|
+
# above copyright notice is included.
|
9
|
+
|
10
|
+
|
11
|
+
require 'test/spec'
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'flexmock'
|
15
|
+
rescue LoadError
|
16
|
+
context "flexmock" do
|
17
|
+
specify "can not be found. BAIL OUT!" do
|
18
|
+
end
|
19
|
+
end
|
20
|
+
else
|
21
|
+
|
22
|
+
context "flexmock" do
|
23
|
+
include FlexMock::TestCase
|
24
|
+
|
25
|
+
setup do
|
26
|
+
@mock = FlexMock.new
|
27
|
+
end
|
28
|
+
|
29
|
+
specify "should handle" do
|
30
|
+
args = nil
|
31
|
+
@mock.mock_handle(:hi) { |a, b| args = [a,b] }
|
32
|
+
@mock.hi(1,2)
|
33
|
+
args.should.equal [1,2]
|
34
|
+
end
|
35
|
+
|
36
|
+
specify "should handle without a block" do
|
37
|
+
lambda {
|
38
|
+
@mock.mock_handle(:blip)
|
39
|
+
@mock.blip
|
40
|
+
}.should.not.raise
|
41
|
+
end
|
42
|
+
|
43
|
+
specify "should handle with a block" do
|
44
|
+
called = false
|
45
|
+
@mock.mock_handle(:blip) { |block| block.call }
|
46
|
+
@mock.blip { called = true }
|
47
|
+
called.should.be true
|
48
|
+
end
|
49
|
+
|
50
|
+
specify "should have a return value" do
|
51
|
+
@mock.mock_handle(:blip) { 10 }
|
52
|
+
@mock.blip.should.equal 10
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "should handle missing methods" do
|
56
|
+
ex = lambda {
|
57
|
+
@mock.not_defined
|
58
|
+
}.should.raise(NoMethodError)
|
59
|
+
ex.message.should.match(/not_defined/)
|
60
|
+
end
|
61
|
+
|
62
|
+
specify "should ignore missing methods" do
|
63
|
+
lambda {
|
64
|
+
@mock.mock_ignore_missing
|
65
|
+
@mock.blip
|
66
|
+
}.should.not.raise
|
67
|
+
end
|
68
|
+
|
69
|
+
specify "should count correctly" do
|
70
|
+
@mock.mock_handle(:blip, 3)
|
71
|
+
@mock.blip
|
72
|
+
@mock.blip
|
73
|
+
@mock.blip
|
74
|
+
lambda { @mock.mock_verify }.should.not.raise Test::Unit::AssertionFailedError
|
75
|
+
end
|
76
|
+
|
77
|
+
specify "should raise on bad counts" do
|
78
|
+
@mock.mock_handle(:blip, 3)
|
79
|
+
@mock.blip
|
80
|
+
@mock.blip
|
81
|
+
lambda { @mock.mock_verify }.should.raise Test::Unit::AssertionFailedError
|
82
|
+
end
|
83
|
+
|
84
|
+
specify "should handle undetermined counts" do
|
85
|
+
lambda {
|
86
|
+
FlexMock.use('fs') { |m|
|
87
|
+
m.mock_handle(:blip)
|
88
|
+
m.blip
|
89
|
+
m.blip
|
90
|
+
m.blip
|
91
|
+
}
|
92
|
+
}.should.not.raise Test::Unit::AssertionFailedError
|
93
|
+
end
|
94
|
+
|
95
|
+
specify "should handle zero counts" do
|
96
|
+
lambda {
|
97
|
+
FlexMock.use { |m|
|
98
|
+
m.mock_handle(:blip, 0)
|
99
|
+
m.blip
|
100
|
+
}
|
101
|
+
}.should.raise Test::Unit::AssertionFailedError
|
102
|
+
end
|
103
|
+
|
104
|
+
specify "should have file IO with use" do
|
105
|
+
file = FlexMock.use do |m|
|
106
|
+
filedata = ["line 1", "line 2"]
|
107
|
+
m.mock_handle(:gets, 3) { filedata.shift }
|
108
|
+
count_lines(m).should.equal 2
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def count_lines(stream)
|
113
|
+
result = 0
|
114
|
+
while line = stream.gets
|
115
|
+
result += 1
|
116
|
+
end
|
117
|
+
result
|
118
|
+
end
|
119
|
+
|
120
|
+
specify "should have use" do
|
121
|
+
lambda {
|
122
|
+
FlexMock.use do |m|
|
123
|
+
m.mock_handle(:blip, 2)
|
124
|
+
m.blip
|
125
|
+
end
|
126
|
+
}.should.raise Test::Unit::AssertionFailedError
|
127
|
+
end
|
128
|
+
|
129
|
+
specify "should handle failures during use" do
|
130
|
+
ex = lambda {
|
131
|
+
FlexMock.use do |m|
|
132
|
+
m.mock_handle(:blip, 2)
|
133
|
+
xyz
|
134
|
+
end
|
135
|
+
}.should.raise NameError
|
136
|
+
ex.message.should.match(/undefined local variable or method/)
|
137
|
+
end
|
138
|
+
|
139
|
+
specify "should deal with sequential values" do
|
140
|
+
values = [1,4,9,16]
|
141
|
+
@mock.mock_handle(:get) { values.shift }
|
142
|
+
@mock.get.should.equal 1
|
143
|
+
@mock.get.should.equal 4
|
144
|
+
@mock.get.should.equal 9
|
145
|
+
@mock.get.should.equal 16
|
146
|
+
end
|
147
|
+
|
148
|
+
specify "respond_to? should return false for non handled methods" do
|
149
|
+
@mock.should.not.respond_to :blah
|
150
|
+
end
|
151
|
+
|
152
|
+
specify "respond_to? should return true for explicit methods" do
|
153
|
+
@mock.mock_handle(:xyz)
|
154
|
+
@mock.should.respond_to :xyz
|
155
|
+
end
|
156
|
+
|
157
|
+
specify "respond_to? should return true when ignoring_missing" do
|
158
|
+
@mock.mock_ignore_missing
|
159
|
+
@mock.should.respond_to :yada
|
160
|
+
end
|
161
|
+
|
162
|
+
specify "respond_to? should return true for missing_methods when should_ignore_missing" do
|
163
|
+
@mock.should_ignore_missing
|
164
|
+
@mock.should.respond_to :yada
|
165
|
+
end
|
166
|
+
|
167
|
+
specify "should raise error on unknown method proc" do
|
168
|
+
lambda {
|
169
|
+
@mock.method(:xyzzy)
|
170
|
+
}.should.raise NameError
|
171
|
+
end
|
172
|
+
|
173
|
+
specify "should return callable proc on method" do
|
174
|
+
got_it = false
|
175
|
+
@mock.mock_handle(:xyzzy) { got_it = true }
|
176
|
+
method_proc = @mock.method(:xyzzy)
|
177
|
+
method_proc.should.not.be.nil
|
178
|
+
method_proc.call
|
179
|
+
got_it.should.be true
|
180
|
+
end
|
181
|
+
|
182
|
+
specify "should return do nothing proc for missing methods" do
|
183
|
+
@mock.mock_ignore_missing
|
184
|
+
method_proc = @mock.method(:plugh)
|
185
|
+
method_proc.should.not.be.nil
|
186
|
+
lambda { method_proc.call }.should.not.raise
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
|
191
|
+
class TemperatureSampler
|
192
|
+
def initialize(sensor)
|
193
|
+
@sensor = sensor
|
194
|
+
end
|
195
|
+
|
196
|
+
def average_temp
|
197
|
+
total = (0...3).collect { @sensor.read_temperature }.inject { |i, s| i + s }
|
198
|
+
total / 3.0
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "flexmock" do
|
203
|
+
include FlexMock::TestCase
|
204
|
+
|
205
|
+
specify "works with test/spec" do
|
206
|
+
sensor = flexmock("temp")
|
207
|
+
sensor.should_receive(:read_temperature).times(3).and_return(10, 12, 14)
|
208
|
+
|
209
|
+
sampler = TemperatureSampler.new(sensor)
|
210
|
+
sampler.average_temp.should.equal 12
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end # if not rescue LoadError
|