require 'test/unit/assertionfailederror'
require 'test/unit/util/backtracefilter'
module Test
module Unit
module Assertions
public
def assert_block(message="assert_block failed.") _wrap_assertion do
if (! yield)
raise AssertionFailedError.new(message.to_s)
end
end
end
public
def assert(boolean, message=nil)
_wrap_assertion do
assert_block("assert should not be called with a block.") { !block_given? }
assert_block(build_message(message, "<?> is not true.", boolean)) { boolean }
end
end
public
def assert_equal(expected, actual, message=nil)
full_message = build_message(message, <<EOT, expected, actual)
<?> expected but was
<?>.
EOT
assert_block(full_message) { expected == actual }
end
private
def _check_exception_class(args) args.partition do |klass|
next if klass.instance_of?(Module)
assert(Exception >= klass, "Should expect a class of exception, #{klass}")
true
end
end
private
def _expected_exception?(actual_exception, exceptions, modules) exceptions.include?(actual_exception.class) or
modules.any? {|mod| actual_exception.is_a?(mod)}
end
public
def assert_raise(*args)
_wrap_assertion do
if Module === args.last
message = ""
else
message = args.pop
end
exceptions, modules = _check_exception_class(args)
expected = args.size == 1 ? args.first : args
actual_exception = nil
full_message = build_message(message, "<?> exception expected but none was thrown.", expected)
assert_block(full_message) do
begin
yield
rescue Exception => actual_exception
break
end
false
end
full_message = build_message(message, "<?> exception expected but was\n?", expected, actual_exception)
assert_block(full_message) {_expected_exception?(actual_exception, exceptions, modules)}
actual_exception
end
end
public
def assert_raises(*args, &block)
assert_raise(*args, &block)
end
public
def assert_instance_of(klass, object, message="")
_wrap_assertion do
assert_equal(Class, klass.class, "assert_instance_of takes a Class as its first argument")
full_message = build_message(message, <<EOT, object, klass, object.class)
<?> expected to be an instance of
<?> but was
<?>.
EOT
assert_block(full_message){object.instance_of?(klass)}
end
end
public
def assert_nil(object, message="")
assert_equal(nil, object, message)
end
public
def assert_kind_of(klass, object, message="")
_wrap_assertion do
assert(klass.kind_of?(Module), "The first parameter to assert_kind_of should be a kind_of Module.")
full_message = build_message(message, "<?>\nexpected to be kind_of\\?\n<?> but was\n<?>.", object, klass, object.class)
assert_block(full_message){object.kind_of?(klass)}
end
end
public
def assert_respond_to(object, method, message="")
_wrap_assertion do
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)
assert_block(full_message) do
method.kind_of?(Symbol) || method.respond_to?(:to_str)
end
full_message = build_message(message, <<EOT, object, object.class, method)
<?>
of type <?>
expected to respond_to\\?<?>.
EOT
assert_block(full_message) { object.respond_to?(method) }
end
end
public
def assert_match(pattern, string, message="")
_wrap_assertion do
pattern = case(pattern)
when String
Regexp.new(Regexp.escape(pattern))
else
pattern
end
full_message = build_message(message, "<?> expected to be =~\n<?>.", string, pattern)
assert_block(full_message) { string =~ pattern }
end
end
public
def assert_same(expected, actual, message="")
full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
<?>
with id <?> expected to be equal\\? to
<?>
with id <?>.
EOT
assert_block(full_message) { actual.equal?(expected) }
end
public
def assert_operator(object1, operator, object2, message="")
_wrap_assertion do
full_message = build_message(nil, "<?>\ngiven as the operator for #assert_operator must be a Symbol or #respond_to\\?(:to_str).", operator)
assert_block(full_message){operator.kind_of?(Symbol) || operator.respond_to?(:to_str)}
full_message = build_message(message, <<EOT, object1, AssertionMessage.literal(operator), object2)
<?> expected to be
?
<?>.
EOT
assert_block(full_message) { object1.__send__(operator, object2) }
end
end
public
def assert_nothing_raised(*args)
_wrap_assertion do
if Module === args.last
message = ""
else
message = args.pop
end
exceptions, modules = _check_exception_class(args)
begin
yield
rescue Exception => e
if ((args.empty? && !e.instance_of?(AssertionFailedError)) ||
_expected_exception?(e, exceptions, modules))
assert_block(build_message(message, "Exception raised:\n?", e)){false}
else
raise
end
end
nil
end
end
public
def flunk(message="Flunked")
assert_block(build_message(message)){false}
end
public
def assert_not_same(expected, actual, message="")
full_message = build_message(message, <<EOT, expected, expected.__id__, actual, actual.__id__)
<?>
with id <?> expected to not be equal\\? to
<?>
with id <?>.
EOT
assert_block(full_message) { !actual.equal?(expected) }
end
public
def assert_not_equal(expected, actual, message="")
full_message = build_message(message, "<?> expected to be != to\n<?>.", expected, actual)
assert_block(full_message) { expected != actual }
end
public
def assert_not_nil(object, message="")
full_message = build_message(message, "<?> expected to not be nil.", object)
assert_block(full_message){!object.nil?}
end
public
def assert_no_match(regexp, string, message="")
_wrap_assertion do
assert_instance_of(Regexp, regexp, "The first argument to assert_no_match should be a Regexp.")
full_message = build_message(message, "<?> expected to not match\n<?>.", regexp, string)
assert_block(full_message) { regexp !~ string }
end
end
UncaughtThrow = {NameError => /^uncaught throw \`(.+)\'$/,
ThreadError => /^uncaught throw \`(.+)\' in thread /}
public
def assert_throws(expected_symbol, message="", &proc)
_wrap_assertion do
assert_instance_of(Symbol, expected_symbol, "assert_throws expects the symbol that should be thrown for its first argument")
assert_block("Should have passed a block to assert_throws."){block_given?}
caught = true
begin
catch(expected_symbol) do
proc.call
caught = false
end
full_message = build_message(message, "<?> should have been thrown.", expected_symbol)
assert_block(full_message){caught}
rescue NameError, ThreadError => error
if UncaughtThrow[error.class] !~ error.message
raise error
end
full_message = build_message(message, "<?> expected to be thrown but\n<?> was thrown.", expected_symbol, $1.intern)
flunk(full_message)
end
end
end
public
def assert_nothing_thrown(message="", &proc)
_wrap_assertion do
assert(block_given?, "Should have passed a block to assert_nothing_thrown")
begin
proc.call
rescue NameError, ThreadError => error
if UncaughtThrow[error.class] !~ error.message
raise error
end
full_message = build_message(message, "<?> was thrown when nothing was expected", $1.intern)
flunk(full_message)
end
assert(true, "Expected nothing to be thrown")
end
end
public
def assert_in_delta(expected_float, actual_float, delta, message="")
_wrap_assertion do
{expected_float => "first float", actual_float => "second float", delta => "delta"}.each do |float, name|
assert_respond_to(float, :to_f, "The arguments must respond to to_f; the #{name} did not")
end
assert_operator(delta, :>=, 0.0, "The delta should not be negative")
full_message = build_message(message, <<EOT, expected_float, actual_float, delta)
<?> and
<?> expected to be within
<?> of each other.
EOT
assert_block(full_message) { (expected_float.to_f - actual_float.to_f).abs <= delta.to_f }
end
end
public
def assert_send(send_array, message="")
_wrap_assertion do
assert_instance_of(Array, send_array, "assert_send requires an array of send information")
assert(send_array.size >= 2, "assert_send requires at least a receiver and a message name")
full_message = build_message(message, <<EOT, send_array[0], AssertionMessage.literal(send_array[1].to_s), send_array[2..-1])
<?> expected to respond to
<?(?)> with a true value.
EOT
assert_block(full_message) { send_array[0].__send__(send_array[1], *send_array[2..-1]) }
end
end
public
def build_message(head, template=nil, *arguments)
template &&= template.chomp
return AssertionMessage.new(head, template, arguments)
end
private
def _wrap_assertion
@_assertion_wrapped ||= false
unless (@_assertion_wrapped)
@_assertion_wrapped = true
begin
add_assertion
return yield
ensure
@_assertion_wrapped = false
end
else
return yield
end
end
private
def add_assertion
end
public
def self.use_pp=(value)
AssertionMessage.use_pp = value
end
class AssertionMessage
@use_pp = true
class << self
attr_accessor :use_pp
end
class Literal
def initialize(value)
@value = value
end
def inspect
@value.to_s
end
end
class Template
def self.create(string)
parts = (string ? string.scan(/(?=[^\\])\?|(?:\\\?|[^\?])+/m) : [])
self.new(parts)
end
attr_reader :count
def initialize(parts)
@parts = parts
@count = parts.find_all{|e| e == '?'}.size
end
def result(parameters)
raise "The number of parameters does not match the number of substitutions." if(parameters.size != count)
params = parameters.dup
@parts.collect{|e| e == '?' ? params.shift : e.gsub(/\\\?/m, '?')}.join('')
end
end
def self.literal(value)
Literal.new(value)
end
include Util::BacktraceFilter
def initialize(head, template_string, parameters)
@head = head
@template_string = template_string
@parameters = parameters
end
def convert(object)
case object
when Exception
<<EOM.chop
Class: <#{convert(object.class)}>
Message: <#{convert(object.message)}>
---Backtrace---
#{filter_backtrace(object.backtrace).join("\n")}
---------------
EOM
else
if(self.class.use_pp)
begin
require 'pp'
rescue LoadError
self.class.use_pp = false
return object.inspect
end unless(defined?(PP))
PP.pp(object, '').chomp
else
object.inspect
end
end
end
def template
@template ||= Template.create(@template_string)
end
def add_period(string)
(string =~ /\.\Z/ ? string : string + '.')
end
def to_s
message_parts = []
if (@head)
head = @head.to_s
unless(head.empty?)
message_parts << add_period(head)
end
end
tail = template.result(@parameters.collect{|e| convert(e)})
message_parts << tail unless(tail.empty?)
message_parts.join("\n")
end
end
end
end
end