rspec-unit 0.9.22
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/Gemfile +14 -0
- data/Gemfile.lock +34 -0
- data/LICENSE +20 -0
- data/README.md +121 -0
- data/Rakefile +49 -0
- data/VERSION.yml +4 -0
- data/lib/rspec-unit.rb +1 -0
- data/lib/rspec/unit.rb +3 -0
- data/lib/rspec/unit/assertions.rb +651 -0
- data/lib/rspec/unit/test_case.rb +188 -0
- data/spec/assertions_spec.rb +528 -0
- data/spec/spec_helper.rb +63 -0
- data/spec/test_case_spec.rb +403 -0
- metadata +96 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
diff-lcs (1.1.2)
|
5
|
+
gemcutter (0.6.1)
|
6
|
+
git (1.2.5)
|
7
|
+
jeweler (1.4.0)
|
8
|
+
gemcutter (>= 0.1.0)
|
9
|
+
git (>= 1.2.5)
|
10
|
+
rubyforge (>= 2.0.0)
|
11
|
+
json_pure (1.4.6)
|
12
|
+
rake (0.8.7)
|
13
|
+
rcov (0.9.9)
|
14
|
+
rspec (2.0.0.beta.22)
|
15
|
+
rspec-core (= 2.0.0.beta.22)
|
16
|
+
rspec-expectations (= 2.0.0.beta.22)
|
17
|
+
rspec-mocks (= 2.0.0.beta.22)
|
18
|
+
rspec-core (2.0.0.beta.22)
|
19
|
+
rspec-expectations (2.0.0.beta.22)
|
20
|
+
diff-lcs (>= 1.1.2)
|
21
|
+
rspec-mocks (2.0.0.beta.22)
|
22
|
+
rspec-core (= 2.0.0.beta.22)
|
23
|
+
rspec-expectations (= 2.0.0.beta.22)
|
24
|
+
rubyforge (2.0.4)
|
25
|
+
json_pure (>= 1.1.7)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
jeweler (>= 1.4.0)
|
32
|
+
rake (>= 0.8.7)
|
33
|
+
rcov (>= 0.9.9)
|
34
|
+
rspec (= 2.0.0.beta.22)
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009, 2010 Glenn Vanderburg
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
# rspec-unit
|
2
|
+
|
3
|
+
test/unit compatibility for RSpec 2.
|
4
|
+
|
5
|
+
## Summary
|
6
|
+
|
7
|
+
rspec-unit adds support for test/unit-style assertions and test
|
8
|
+
cases to RSpec 2. This is useful for piecemeal conversions of your
|
9
|
+
test suite (in either direction), mixing styles, or if you simply
|
10
|
+
want to use test/unit-style assertions occasionally in your specs.
|
11
|
+
|
12
|
+
Just add this to your code:
|
13
|
+
|
14
|
+
require 'rspec/unit'
|
15
|
+
|
16
|
+
and then you can write test classes like this:
|
17
|
+
|
18
|
+
class FooTest < RSpec::Unit::TestCase
|
19
|
+
def test_foo
|
20
|
+
assert_equal 3, Foo::major_version
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Using the `test_info` method, you can attach metadata to the next
|
25
|
+
defined test (this works much the same way Rake's `desc` method
|
26
|
+
attaches a description string to the next defined task):
|
27
|
+
|
28
|
+
test_info :speed => 'slow', :run => 'nightly'
|
29
|
+
def test_tarantula_multipass
|
30
|
+
# ...
|
31
|
+
end
|
32
|
+
|
33
|
+
You can also attach metadata to the entire class with the
|
34
|
+
`test_case_info` method:
|
35
|
+
|
36
|
+
class BarTest < RSpec::Unit::TestCase
|
37
|
+
test_case_info :integration => true
|
38
|
+
|
39
|
+
# ...
|
40
|
+
end
|
41
|
+
|
42
|
+
Each instance of `Rspec::Unit::TestCase` is equivalent to an
|
43
|
+
RSpec `describe` block, so it can also include `example` blocks,
|
44
|
+
`before` and `after` blocks, and nested `describe` blocks. Test
|
45
|
+
methods and `example` blocks can contain either assertions or `should`
|
46
|
+
expressions. `test` blocks (as found in Rails 2.x) also work.
|
47
|
+
|
48
|
+
Additionally, assertions can be used inside ordinary RSpec
|
49
|
+
examples.
|
50
|
+
|
51
|
+
## Rationale
|
52
|
+
|
53
|
+
This gem is the rough equivalent, for RSpec 2, of the test/unit
|
54
|
+
compatibility that was a part of the core RSpec gem in RSpec 1.
|
55
|
+
The new RSpec runner design makes it quite easy to implement this
|
56
|
+
functionality as a separate gem, which seems like a better choice
|
57
|
+
in many ways.
|
58
|
+
|
59
|
+
Currently, test/unit compatibility is much more limited than in
|
60
|
+
RSpec 1. The goal is not to make RSpec 2 a drop-in replacement for
|
61
|
+
test/unit; rather, we have two more limited goals:
|
62
|
+
|
63
|
+
1. to allow RSpec 2 examples to easily make use of test/unit assertions
|
64
|
+
in cases where those assertions are valuable, or where assertions
|
65
|
+
might be the best way to express particular expectations.
|
66
|
+
2. to make it *easy* for a project to switch an existing test/unit
|
67
|
+
suite over to run under RSpec, as the start of a gradual, piecemeal
|
68
|
+
conversion to RSpec.
|
69
|
+
|
70
|
+
As such, there are some things we don''t support:
|
71
|
+
|
72
|
+
* The top-level module name is different. For example, one requires
|
73
|
+
`rspec/unit` rather than `test/unit`, and extends `RSpec::Unit::TestCase`
|
74
|
+
rather than `Test::Unit::TestCase`.
|
75
|
+
* TestSuite is not supported. The RSpec 2 metadata features are
|
76
|
+
far more flexible than test/unit-style suites.
|
77
|
+
* Because of the very different implementation, many test/unit extensions
|
78
|
+
will not run properly.
|
79
|
+
* All test output and summaries are in RSpec style; test/unit-compatible
|
80
|
+
output is not supported.
|
81
|
+
|
82
|
+
We will certainly consider supporting those things if there is demand.
|
83
|
+
|
84
|
+
I originally wrote this test/unit compatibility gem for Micronaut, a
|
85
|
+
lightweight RSpec clone by Chad Humphries. Micronaut has been rolled
|
86
|
+
into RSpec as the core of RSpec 2, and I was able to move the test/unit
|
87
|
+
compatibility over with minimal changes.
|
88
|
+
|
89
|
+
The point of this gem is not that I think test/unit is a better way
|
90
|
+
to write tests than the RSpec style. I admit that I'm a TDD oldtimer
|
91
|
+
who sees RSpec as mostly a cosmetic (rather than fundamental) change,
|
92
|
+
but that doesn't mean it's not an important change. My curmudgeonly
|
93
|
+
nature has its limits, and I do find specs a big improvement.
|
94
|
+
|
95
|
+
So why rspec-unit? Three reasons:
|
96
|
+
|
97
|
+
1. I wanted to show off the generality of Micronaut's (and now RSpec's)
|
98
|
+
architecture. I hope rspec-unit can serve as an example for anyone
|
99
|
+
who wants to experiment with new ways of expressing tests and specs
|
100
|
+
on top of RSpec.
|
101
|
+
2. Many projects with existing test/unit test suites might want to
|
102
|
+
benefit from the [metadata goodness][metadata] in RSpec 2, or begin
|
103
|
+
a gradual, piecemeal change to an RSpec style. That's pretty
|
104
|
+
easy to do with rspec-unit.
|
105
|
+
3. Even when writing specs and examples, I frequently encounter
|
106
|
+
cases where an assertion is more expressive than a `should`
|
107
|
+
expression. It's nice just to have assertions supported within
|
108
|
+
RSpec examples.
|
109
|
+
|
110
|
+
[uth]: http://blog.thinkrelevance.com/2009/4/1/micronaut-innovation-under-the-hood
|
111
|
+
[metadata]: http://blog.thinkrelevance.com/2009/3/26/introducing-micronaut-a-lightweight-bdd-framework
|
112
|
+
|
113
|
+
## To Do
|
114
|
+
|
115
|
+
It would be nice to try using the assertion code from minitest,
|
116
|
+
which is much more compact and seems less coupled than that from
|
117
|
+
test/unit.
|
118
|
+
|
119
|
+
### Copyright
|
120
|
+
|
121
|
+
Copyright (c) 2009, 2010 Glenn Vanderburg. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'bundler/setup'
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'jeweler'
|
5
|
+
Jeweler::Tasks.new do |gem|
|
6
|
+
gem.name = "rspec-unit"
|
7
|
+
gem.summary = %Q{test/unit compatibility for RSpec 2.}
|
8
|
+
gem.description = gem.summary # File.read('README.md').sub(/\A.*^## Summary\s*$\s*(.*?)\s*^#+\s.*\Z/m, '\1')
|
9
|
+
gem.email = "glv@vanderburg.org"
|
10
|
+
gem.homepage = "http://github.com/glv/rspec-unit"
|
11
|
+
gem.authors = ["Glenn Vanderburg"]
|
12
|
+
gem.rubyforge_project = "rspec-unit"
|
13
|
+
gem.add_dependency('rspec', '~> 2.0')
|
14
|
+
gem.has_rdoc = false
|
15
|
+
gem.files = FileList["[A-Z]*", "{bin,lib,spec}/**/*"]
|
16
|
+
gem.rubyforge_project = 'glv'
|
17
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
18
|
+
end
|
19
|
+
|
20
|
+
Jeweler::RubyforgeTasks.new
|
21
|
+
Jeweler::GemcutterTasks.new
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'rspec/core/rake_task'
|
27
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
28
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
29
|
+
spec.ruby_opts = '-Ilib -Ispec'
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
33
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
34
|
+
spec.rcov_opts = '-Ilib -Ispec -x ' + "'#{Regexp.escape(Bundler.settings.path)},^spec/'"
|
35
|
+
spec.rcov = true
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :spec
|
39
|
+
|
40
|
+
require 'rake/rdoctask'
|
41
|
+
Rake::RDocTask.new do |rdoc|
|
42
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
43
|
+
|
44
|
+
rdoc.rdoc_dir = 'rdoc'
|
45
|
+
rdoc.title = "rspec-unit #{version}"
|
46
|
+
rdoc.rdoc_files.include('README*')
|
47
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
48
|
+
end
|
49
|
+
|
data/VERSION.yml
ADDED
data/lib/rspec-unit.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'rspec/unit'
|
data/lib/rspec/unit.rb
ADDED
@@ -0,0 +1,651 @@
|
|
1
|
+
# Author:: Nathaniel Talbott.
|
2
|
+
# Copyright:: Copyright (c) 2000-2003 Nathaniel Talbott. All rights reserved.
|
3
|
+
# License:: Ruby license.
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module Unit
|
7
|
+
|
8
|
+
##
|
9
|
+
# Test::Unit::Assertions contains the standard Test::Unit assertions.
|
10
|
+
# Assertions is included in Test::Unit::TestCase.
|
11
|
+
#
|
12
|
+
# To include it in your own code and use its functionality, you simply
|
13
|
+
# need to rescue Test::Unit::AssertionFailedError. Additionally you may
|
14
|
+
# override add_assertion to get notified whenever an assertion is made.
|
15
|
+
#
|
16
|
+
# Notes:
|
17
|
+
# * The message to each assertion, if given, will be propagated with the
|
18
|
+
# failure.
|
19
|
+
# * It is easy to add your own assertions based on assert_block().
|
20
|
+
#
|
21
|
+
# = Example Custom Assertion
|
22
|
+
#
|
23
|
+
# def deny(boolean, message = nil)
|
24
|
+
# message = build_message message, '<?> is not false or nil.', boolean
|
25
|
+
# assert_block message do
|
26
|
+
# not boolean
|
27
|
+
# end
|
28
|
+
# end
|
29
|
+
|
30
|
+
module Assertions
|
31
|
+
|
32
|
+
##
|
33
|
+
# The assertion upon which all other assertions are based. Passes if the
|
34
|
+
# block yields true.
|
35
|
+
#
|
36
|
+
# Example:
|
37
|
+
# assert_block "Couldn't do the thing" do
|
38
|
+
# do_the_thing
|
39
|
+
# end
|
40
|
+
|
41
|
+
public
|
42
|
+
def assert_block(message="assert_block failed.") # :yields:
|
43
|
+
_wrap_assertion do
|
44
|
+
if (! yield)
|
45
|
+
raise AssertionFailedError.new(message.to_s)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# Asserts that +boolean+ is not false or nil.
|
52
|
+
#
|
53
|
+
# Example:
|
54
|
+
# assert [1, 2].include?(5)
|
55
|
+
|
56
|
+
public
|
57
|
+
def assert(boolean, message=nil)
|
58
|
+
_wrap_assertion do
|
59
|
+
assert_block("assert should not be called with a block.") { !block_given? }
|
60
|
+
assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Passes if +expected+ == +actual.
|
66
|
+
#
|
67
|
+
# Note that the ordering of arguments is important, since a helpful
|
68
|
+
# error message is generated when this one fails that tells you the
|
69
|
+
# values of expected and actual.
|
70
|
+
#
|
71
|
+
# Example:
|
72
|
+
# assert_equal 'MY STRING', 'my string'.upcase
|
73
|
+
|
74
|
+
public
|
75
|
+
def assert_equal(expected, actual, message=nil)
|
76
|
+
full_message = build_message(message, <<EOT, expected, actual)
|
77
|
+
<?> expected but was
|
78
|
+
<?>.
|
79
|
+
EOT
|
80
|
+
assert_block(full_message) { expected == actual }
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
def _check_exception_class(args) # :nodoc:
|
85
|
+
args.partition do |klass|
|
86
|
+
next if klass.instance_of?(Module)
|
87
|
+
assert(Exception >= klass, "Should expect a class of exception, #{klass}")
|
88
|
+
true
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
private
|
93
|
+
def _expected_exception?(actual_exception, exceptions, modules) # :nodoc:
|
94
|
+
exceptions.include?(actual_exception.class) or
|
95
|
+
modules.any? {|mod| actual_exception.is_a?(mod)}
|
96
|
+
end
|
97
|
+
|
98
|
+
##
|
99
|
+
# Passes if the block raises one of the given exceptions.
|
100
|
+
#
|
101
|
+
# Example:
|
102
|
+
# assert_raise RuntimeError, LoadError do
|
103
|
+
# raise 'Boom!!!'
|
104
|
+
# end
|
105
|
+
|
106
|
+
public
|
107
|
+
def assert_raise(*args)
|
108
|
+
_wrap_assertion do
|
109
|
+
if Module === args.last
|
110
|
+
message = ""
|
111
|
+
else
|
112
|
+
message = args.pop
|
113
|
+
end
|
114
|
+
exceptions, modules = _check_exception_class(args)
|
115
|
+
expected = args.size == 1 ? args.first : args
|
116
|
+
actual_exception = nil
|
117
|
+
full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
|
118
|
+
assert_block(full_message) do
|
119
|
+
begin
|
120
|
+
yield
|
121
|
+
rescue Exception => actual_exception
|
122
|
+
break
|
123
|
+
end
|
124
|
+
false
|
125
|
+
end
|
126
|
+
full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
|
127
|
+
assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
|
128
|
+
actual_exception
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Alias of assert_raise.
|
134
|
+
#
|
135
|
+
# Will be deprecated in 1.9, and removed in 2.0.
|
136
|
+
|
137
|
+
public
|
138
|
+
def assert_raises(*args, &block)
|
139
|
+
assert_raise(*args, &block)
|
140
|
+
end
|
141
|
+
|
142
|
+
##
|
143
|
+
# Passes if +object+ .instance_of? +klass+
|
144
|
+
#
|
145
|
+
# Example:
|
146
|
+
# assert_instance_of String, 'foo'
|
147
|
+
|
148
|
+
public
|
149
|
+
def assert_instance_of(klass, object, message="")
|
150
|
+
_wrap_assertion do
|
151
|
+
assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
|
152
|
+
full_message = build_message(message, <<EOT, object, klass, object.class)
|
153
|
+
<?> expected to be an instance of
|
154
|
+
<?> but was
|
155
|
+
<?>.
|
156
|
+
EOT
|
157
|
+
assert_block(full_message){object.instance_of?(klass)}
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
##
|
162
|
+
# Passes if +object+ is nil.
|
163
|
+
#
|
164
|
+
# Example:
|
165
|
+
# assert_nil [1, 2].uniq!
|
166
|
+
|
167
|
+
public
|
168
|
+
def assert_nil(object, message="")
|
169
|
+
assert_equal(nil, object, message)
|
170
|
+
end
|
171
|
+
|
172
|
+
##
|
173
|
+
# Passes if +object+ .kind_of? +klass+
|
174
|
+
#
|
175
|
+
# Example:
|
176
|
+
# assert_kind_of Object, 'foo'
|
177
|
+
|
178
|
+
public
|
179
|
+
def assert_kind_of(klass, object, message="")
|
180
|
+
_wrap_assertion do
|
181
|
+
assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
|
182
|
+
full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
|
183
|
+
assert_block(full_message){object.kind_of?(klass)}
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
##
|
188
|
+
# Passes if +object+ .respond_to? +method+
|
189
|
+
#
|
190
|
+
# Example:
|
191
|
+
# assert_respond_to 'bugbear', :slice
|
192
|
+
|
193
|
+
public
|
194
|
+
def assert_respond_to(object, method, message="")
|
195
|
+
_wrap_assertion do
|
196
|
+
full_message = build_message(nil, "<?>\ngiven as the method name argument to #assert_respond_to must be a Symbol or #respond_to\\?(:to_str).", method)
|
197
|
+
|
198
|
+
assert_block(full_message) do
|
199
|
+
method.kind_of?(Symbol) || method.respond_to?(:to_str)
|
200
|
+
end
|
201
|
+
full_message = build_message(message, <<EOT, object, object.class, method)
|
202
|
+
<?>
|
203
|
+
of type <?>
|
204
|
+
expected to respond_to\\?<?>.
|
205
|
+
EOT
|
206
|
+
assert_block(full_message) { object.respond_to?(method) }
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
##
|
211
|
+
# Passes if +string+ =~ +pattern+.
|
212
|
+
#
|
213
|
+
# Example:
|
214
|
+
# assert_match(/\d+/, 'five, 6, seven')
|
215
|
+
|
216
|
+
public
|
217
|
+
def assert_match(pattern, string, message="")
|
218
|
+
_wrap_assertion do
|
219
|
+
pattern = case(pattern)
|
220
|
+
when String
|
221
|
+
Regexp.new(Regexp.escape(pattern))
|
222
|
+
else
|
223
|
+
pattern
|
224
|
+
end
|
225
|
+
full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
|
226
|
+
assert_block(full_message) { string =~ pattern }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
##
|
231
|
+
# Passes if +actual+ .equal? +expected+ (i.e. they are the same
|
232
|
+
# instance).
|
233
|
+
#
|
234
|
+
# Example:
|
235
|
+
# o = Object.new
|
236
|
+
# assert_same o, o
|
237
|
+
|
238
|
+
public
|
239
|
+
def assert_same(expected, actual, message="")
|
240
|
+
full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
|
241
|
+
<?>
|
242
|
+
with id <?> expected to be equal\\? to
|
243
|
+
<?>
|
244
|
+
with id <?>.
|
245
|
+
EOT
|
246
|
+
assert_block(full_message) { actual.equal?(expected) }
|
247
|
+
end
|
248
|
+
|
249
|
+
##
|
250
|
+
# Compares the +object1+ with +object2+ using +operator+.
|
251
|
+
#
|
252
|
+
# Passes if object1.__send__(operator, object2) is true.
|
253
|
+
#
|
254
|
+
# Example:
|
255
|
+
# assert_operator 5, :>=, 4
|
256
|
+
|
257
|
+
public
|
258
|
+
def assert_operator(object1, operator, object2, message="")
|
259
|
+
_wrap_assertion do
|
260
|
+
full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
|
261
|
+
assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
|
262
|
+
full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
|
263
|
+
<?> expected to be
|
264
|
+
?
|
265
|
+
<?>.
|
266
|
+
EOT
|
267
|
+
assert_block(full_message) { object1.__send__(operator, object2) }
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
##
|
272
|
+
# Passes if block does not raise an exception.
|
273
|
+
#
|
274
|
+
# Example:
|
275
|
+
# assert_nothing_raised do
|
276
|
+
# [1, 2].uniq
|
277
|
+
# end
|
278
|
+
|
279
|
+
public
|
280
|
+
def assert_nothing_raised(*args)
|
281
|
+
_wrap_assertion do
|
282
|
+
if Module === args.last
|
283
|
+
message = ""
|
284
|
+
else
|
285
|
+
message = args.pop
|
286
|
+
end
|
287
|
+
exceptions, modules = _check_exception_class(args)
|
288
|
+
begin
|
289
|
+
yield
|
290
|
+
rescue Exception => e
|
291
|
+
if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
|
292
|
+
_expected_exception?(e, exceptions, modules))
|
293
|
+
assert_block(build_message(message, "Exception raised:\n?", e)){false}
|
294
|
+
else
|
295
|
+
raise
|
296
|
+
end
|
297
|
+
end
|
298
|
+
nil
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
##
|
303
|
+
# Flunk always fails.
|
304
|
+
#
|
305
|
+
# Example:
|
306
|
+
# flunk 'Not done testing yet.'
|
307
|
+
|
308
|
+
public
|
309
|
+
def flunk(message="Flunked")
|
310
|
+
assert_block(build_message(message)){false}
|
311
|
+
end
|
312
|
+
|
313
|
+
##
|
314
|
+
# Passes if ! +actual+ .equal? +expected+
|
315
|
+
#
|
316
|
+
# Example:
|
317
|
+
# assert_not_same Object.new, Object.new
|
318
|
+
|
319
|
+
public
|
320
|
+
def assert_not_same(expected, actual, message="")
|
321
|
+
full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
|
322
|
+
<?>
|
323
|
+
with id <?> expected to not be equal\\? to
|
324
|
+
<?>
|
325
|
+
with id <?>.
|
326
|
+
EOT
|
327
|
+
assert_block(full_message) { !actual.equal?(expected) }
|
328
|
+
end
|
329
|
+
|
330
|
+
##
|
331
|
+
# Passes if +expected+ != +actual+
|
332
|
+
#
|
333
|
+
# Example:
|
334
|
+
# assert_not_equal 'some string', 5
|
335
|
+
|
336
|
+
public
|
337
|
+
def assert_not_equal(expected, actual, message="")
|
338
|
+
full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
|
339
|
+
assert_block(full_message) { expected != actual }
|
340
|
+
end
|
341
|
+
|
342
|
+
##
|
343
|
+
# Passes if ! +object+ .nil?
|
344
|
+
#
|
345
|
+
# Example:
|
346
|
+
# assert_not_nil '1 two 3'.sub!(/two/, '2')
|
347
|
+
|
348
|
+
public
|
349
|
+
def assert_not_nil(object, message="")
|
350
|
+
full_message = build_message(message, "<?> expected to not be nil.", object)
|
351
|
+
assert_block(full_message){!object.nil?}
|
352
|
+
end
|
353
|
+
|
354
|
+
##
|
355
|
+
# Passes if +regexp+ !~ +string+
|
356
|
+
#
|
357
|
+
# Example:
|
358
|
+
# assert_no_match(/two/, 'one 2 three')
|
359
|
+
|
360
|
+
public
|
361
|
+
def assert_no_match(regexp, string, message="")
|
362
|
+
_wrap_assertion do
|
363
|
+
assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
|
364
|
+
full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
|
365
|
+
assert_block(full_message) { regexp !~ string }
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
|
370
|
+
ThreadError => /^uncaught throw \`(.+)\' in thread /} #`
|
371
|
+
|
372
|
+
##
|
373
|
+
# Passes if the block throws +expected_symbol+
|
374
|
+
#
|
375
|
+
# Example:
|
376
|
+
# assert_throws :done do
|
377
|
+
# throw :done
|
378
|
+
# end
|
379
|
+
|
380
|
+
public
|
381
|
+
def assert_throws(expected_symbol, message="", &proc)
|
382
|
+
_wrap_assertion do
|
383
|
+
assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
|
384
|
+
assert_block("Should have passed a block to assert_throws."){block_given?}
|
385
|
+
caught = true
|
386
|
+
begin
|
387
|
+
catch(expected_symbol) do
|
388
|
+
proc.call
|
389
|
+
caught = false
|
390
|
+
end
|
391
|
+
full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
|
392
|
+
assert_block(full_message){caught}
|
393
|
+
rescue NameError, ThreadError => error
|
394
|
+
if UncaughtThrow[error.class] !~ error.message
|
395
|
+
raise error
|
396
|
+
end
|
397
|
+
full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
|
398
|
+
flunk(full_message)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
end
|
402
|
+
|
403
|
+
##
|
404
|
+
# Passes if block does not throw anything.
|
405
|
+
#
|
406
|
+
# Example:
|
407
|
+
# assert_nothing_thrown do
|
408
|
+
# [1, 2].uniq
|
409
|
+
# end
|
410
|
+
|
411
|
+
public
|
412
|
+
def assert_nothing_thrown(message="", &proc)
|
413
|
+
_wrap_assertion do
|
414
|
+
assert(block_given?, "Should have passed a block to assert_nothing_thrown")
|
415
|
+
begin
|
416
|
+
proc.call
|
417
|
+
rescue NameError, ThreadError => error
|
418
|
+
if UncaughtThrow[error.class] !~ error.message
|
419
|
+
raise error
|
420
|
+
end
|
421
|
+
full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
|
422
|
+
flunk(full_message)
|
423
|
+
end
|
424
|
+
assert(true, "Expected nothing to be thrown")
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
##
|
429
|
+
# Passes if +expected_float+ and +actual_float+ are equal
|
430
|
+
# within +delta+ tolerance.
|
431
|
+
#
|
432
|
+
# Example:
|
433
|
+
# assert_in_delta 0.05, (50000.0 / 10**6), 0.00001
|
434
|
+
|
435
|
+
public
|
436
|
+
def assert_in_delta(expected_float, actual_float, delta, message="")
|
437
|
+
_wrap_assertion do
|
438
|
+
{expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
|
439
|
+
assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
|
440
|
+
end
|
441
|
+
assert_operator(delta, :>=, 0.0, "The delta should not be negative")
|
442
|
+
full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
|
443
|
+
<?> and
|
444
|
+
<?> expected to be within
|
445
|
+
<?> of each other.
|
446
|
+
EOT
|
447
|
+
assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
|
448
|
+
end
|
449
|
+
end
|
450
|
+
|
451
|
+
##
|
452
|
+
# Passes if the method send returns a true value.
|
453
|
+
#
|
454
|
+
# +send_array+ is composed of:
|
455
|
+
# * A receiver
|
456
|
+
# * A method
|
457
|
+
# * Arguments to the method
|
458
|
+
#
|
459
|
+
# Example:
|
460
|
+
# assert_send [[1, 2], :include?, 4]
|
461
|
+
|
462
|
+
public
|
463
|
+
def assert_send(send_array, message="")
|
464
|
+
_wrap_assertion do
|
465
|
+
assert_instance_of(Array, send_array, "assert_send requires an array of send information")
|
466
|
+
assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
|
467
|
+
full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
|
468
|
+
<?> expected to respond to
|
469
|
+
<?(?)> with a true value.
|
470
|
+
EOT
|
471
|
+
assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
##
|
476
|
+
# Builds a failure message. +head+ is added before the +template+ and
|
477
|
+
# +arguments+ replaces the '?'s positionally in the template.
|
478
|
+
|
479
|
+
public
|
480
|
+
def build_message(head, template=nil, *arguments)
|
481
|
+
template &&= template.chomp
|
482
|
+
return AssertionMessage.new(head, template, arguments)
|
483
|
+
end
|
484
|
+
|
485
|
+
private
|
486
|
+
def _wrap_assertion
|
487
|
+
@_assertion_wrapped ||= false
|
488
|
+
unless (@_assertion_wrapped)
|
489
|
+
@_assertion_wrapped = true
|
490
|
+
begin
|
491
|
+
add_assertion
|
492
|
+
return yield
|
493
|
+
ensure
|
494
|
+
@_assertion_wrapped = false
|
495
|
+
end
|
496
|
+
else
|
497
|
+
return yield
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
##
|
502
|
+
# Called whenever an assertion is made. Define this in classes that
|
503
|
+
# include Test::Unit::Assertions to record assertion counts.
|
504
|
+
|
505
|
+
private
|
506
|
+
def add_assertion
|
507
|
+
end
|
508
|
+
|
509
|
+
##
|
510
|
+
# Select whether or not to use the pretty-printer. If this option is set
|
511
|
+
# to false before any assertions are made, pp.rb will not be required.
|
512
|
+
|
513
|
+
public
|
514
|
+
def self.use_pp=(value)
|
515
|
+
AssertionMessage.use_pp = value
|
516
|
+
end
|
517
|
+
|
518
|
+
# :stopdoc:
|
519
|
+
|
520
|
+
class AssertionMessage
|
521
|
+
@use_pp = true
|
522
|
+
class << self
|
523
|
+
attr_accessor :use_pp
|
524
|
+
end
|
525
|
+
|
526
|
+
class Literal
|
527
|
+
def initialize(value)
|
528
|
+
@value = value
|
529
|
+
end
|
530
|
+
|
531
|
+
def inspect
|
532
|
+
@value.to_s
|
533
|
+
end
|
534
|
+
end
|
535
|
+
|
536
|
+
class Template
|
537
|
+
def self.create(string)
|
538
|
+
parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
|
539
|
+
self.new(parts)
|
540
|
+
end
|
541
|
+
|
542
|
+
attr_reader :count
|
543
|
+
|
544
|
+
def initialize(parts)
|
545
|
+
@parts = parts
|
546
|
+
@count = parts.find_all{|e| e == '?'}.size
|
547
|
+
end
|
548
|
+
|
549
|
+
def result(parameters)
|
550
|
+
raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
|
551
|
+
params = parameters.dup
|
552
|
+
@parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
def self.literal(value)
|
557
|
+
Literal.new(value)
|
558
|
+
end
|
559
|
+
|
560
|
+
def initialize(head, template_string, parameters)
|
561
|
+
@head = head
|
562
|
+
@template_string = template_string
|
563
|
+
@parameters = parameters
|
564
|
+
end
|
565
|
+
|
566
|
+
def convert(object)
|
567
|
+
case object
|
568
|
+
when Exception
|
569
|
+
<<EOM.chop
|
570
|
+
Class: <#{convert(object.class)}>
|
571
|
+
Message: <#{convert(object.message)}>
|
572
|
+
---Backtrace---
|
573
|
+
#{filter_backtrace(object.backtrace).join("\n")}
|
574
|
+
---------------
|
575
|
+
EOM
|
576
|
+
else
|
577
|
+
if(self.class.use_pp)
|
578
|
+
begin
|
579
|
+
require 'pp'
|
580
|
+
rescue LoadError
|
581
|
+
self.class.use_pp = false
|
582
|
+
return object.inspect
|
583
|
+
end unless(defined?(PP))
|
584
|
+
PP.pp(object, '').chomp
|
585
|
+
else
|
586
|
+
object.inspect
|
587
|
+
end
|
588
|
+
end
|
589
|
+
end
|
590
|
+
|
591
|
+
def template
|
592
|
+
@template ||= Template.create(@template_string)
|
593
|
+
end
|
594
|
+
|
595
|
+
def add_period(string)
|
596
|
+
(string =~ /\.\Z/ ? string : string + '.')
|
597
|
+
end
|
598
|
+
|
599
|
+
def to_s
|
600
|
+
message_parts = []
|
601
|
+
if (@head)
|
602
|
+
head = @head.to_s
|
603
|
+
unless(head.empty?)
|
604
|
+
message_parts << add_period(head)
|
605
|
+
end
|
606
|
+
end
|
607
|
+
tail = template.result(@parameters.collect{|e| convert(e)})
|
608
|
+
message_parts << tail unless(tail.empty?)
|
609
|
+
message_parts.join("\n")
|
610
|
+
end
|
611
|
+
|
612
|
+
MICRONAUTUNIT_FILE_SEPARATORS = %r{[\\/:]}
|
613
|
+
MICRONAUTUNIT_PREFIX = __FILE__.split(MICRONAUTUNIT_FILE_SEPARATORS)[0..-3]
|
614
|
+
MICRONAUTUNIT_RB_FILE = /\.rb\Z/
|
615
|
+
|
616
|
+
def filter_backtrace(backtrace, prefix=nil)
|
617
|
+
return ["No backtrace"] unless(backtrace)
|
618
|
+
split_p = if(prefix)
|
619
|
+
prefix.split(MICRONAUTUNIT_FILE_SEPARATORS)
|
620
|
+
else
|
621
|
+
MICRONAUTUNIT_PREFIX
|
622
|
+
end
|
623
|
+
match = proc do |e|
|
624
|
+
split_e = e.split(MICRONAUTUNIT_FILE_SEPARATORS)[0, split_p.size]
|
625
|
+
next false unless(split_e[0..-2] == split_p[0..-2])
|
626
|
+
split_e[-1].sub(MICRONAUTUNIT_RB_FILE, '') == split_p[-1]
|
627
|
+
end
|
628
|
+
return backtrace unless(backtrace.detect(&match))
|
629
|
+
found_prefix = false
|
630
|
+
new_backtrace = backtrace.reverse.reject do |e|
|
631
|
+
if(match[e])
|
632
|
+
found_prefix = true
|
633
|
+
true
|
634
|
+
elsif(found_prefix)
|
635
|
+
false
|
636
|
+
else
|
637
|
+
true
|
638
|
+
end
|
639
|
+
end.reverse
|
640
|
+
new_backtrace = (new_backtrace.empty? ? backtrace : new_backtrace)
|
641
|
+
new_backtrace = new_backtrace.reject(&match)
|
642
|
+
new_backtrace.empty? ? backtrace : new_backtrace
|
643
|
+
end
|
644
|
+
|
645
|
+
end
|
646
|
+
|
647
|
+
# :startdoc:
|
648
|
+
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|