Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
# This is a test/unit clone which was written to practice.
#
# Usage:
#
# require 'simpletest'
#
# class Foo < SimpleTest::TestCase
#
# def test_bar
# assert_equal 1, 1
# end
# end
#
# Original:
# verbose_on, delta_is, assert_
#
module SimpleTest
class Failed < StandardError; end
class Pended < StandardError; end
def self.backtrace(bt)
bt.select {|line| line !~ /#{__FILE__}/ }
end
module Assertions
def assert(test, msg = nil)
unless test
unless msg.instance_of?(Proc)
msg = message(msg) {
" expected true, got false\n\n"
}
end
raise Failed, msg.call
end
self.assertions += 1
true
end
def assert_block(msg = 'assert_block failed', &block)
assert block.call, message(msg)
end
def assert_equal(expected, actual, msg = nil)
msg = message(msg) {
" expected <#{expected}> but\n" +
" got <#{actual}>\n\n"
}
assert expected == actual, msg
end
def assert_in_delta(expected, actual, delta = TestCase.delta, msg = nil)
msg = message(msg) {
" expected <#{expected}> +/- (< #{delta}) but\n" +
" got <#{actual}>\n\n"
}
difference = (expected.to_f - actual.to_f).abs
assert difference <= delta.to_f, msg
end
def assert_instance_of(obj, klass, msg = nil)
msg = message(msg) {
" expected <#{obj.inspect}> is instance of <#{klass}>\n\n"
}
assert obj.instance_of?(klass), msg
end
def assert_kind_of(obj, klass, msg = nil)
msg = message(msg) {
" expected <#{obj.inspect}> is kind of <#{klass}>\n\n"
}
assert obj.kind_of?(klass), msg
end
def assert_match(regexp, string, msg = nil)
fold = string.length > 20
msg = message(msg) {
" expected <#{string.inspect}>" +
(fold ? "\n " : ' ') +
"to match <#{regexp.inspect}>\n\n"
}
regexp = /#{regexp}/ unless regexp.instance_of?(Regexp)
assert regexp =~ string, msg
end
def assert_respond_to(obj, message, msg = nil)
msg = message(msg) {
" expected <#{obj.inspect}> to respond to <:#{message}>\n\n"
}
assert obj.respond_to?(message), msg
end
def assert_nil(object, msg = 'assert_nil failed')
assert object.nil?, message(msg)
end
def assert_same(expected, actual, msg = nil)
msg = message(msg) {
" expected <#{expected}> but\n" +
" got <#{actual}> (using equal?)\n\n"
}
assert expected.equal?(actual), message(msg)
end
def assert_send(send_array, msg = nil)
obj = send_array.shift
meth = send_array.shift
msg = message(msg) {
" expected <#{obj.inspect}> #{meth} <[#{send_array * ','}]> but not\n\n"
}
assert obj.__send__(meth, *send_array), message(msg)
rescue
assert false, message(msg)
end
def assert_throws(expected_symbol = nil, msg = nil, &block)
thrown = true
catch(expected_symbol || :" __ dummy symbol __ ") do
begin
block.call
rescue => e
msg = message(msg) {
"expected <:#{expected_symbol}> but\n" +
" got <#{e.name}> was thrown"
}
thrown = false if expected_symbol
else
msg = message(msg) {
" expected <:#{expected_symbol or 'Symbol'}> but nothing was thrown\n\n"
}
thrown = false
end
end
assert thrown, message(msg)
end
def assert_operator(obj1, operator, obj2, msg = nil)
msg = message(msg) {
" expected <#{obj1.inspect}> #{operator} <#{obj2.inspect}> but not\n\n"
}
assert obj1.__send__(operator, obj2), message(msg)
rescue
assert false, message(msg)
end
def assert_raise(*klass, &block)
msg = nil
msg = klass.pop if klass[-1].instance_of?(String)
raised = false
begin
block.call
rescue => e
if klass.include?(e.class)
raised = true
else
msg = message(msg) {
" expected <#{klass * ','}> but\n" +
" got <#{e.class}>\n" +
" with #{e.message.inspect}\n\n" +
" -----\n" +
" #{SimpleTest.backtrace(e.backtrace).join("\n ")}\n\n"
}
end
else
msg = message(msg) {
" expedted <#{klass * ','}> but nothing raised\n\n"
}
end
assert raised, message(msg)
end
alias assert_raises assert_raise
def assert_not(test, msg = nil)
msg = message(msg) {
" expected 'not' true, got true\n\n"
}
assert !test, message(msg)
end
def assert_no_match(regexp, string, msg = nil)
fold = string.length > 20
msg = message(msg) {
" expected <#{string.inspect}>" +
(fold ? "\n " : ' ') +
"'not' to match <#{regexp.inspect}>\n\n"
}
regexp = /#{regexp}/ unless regexp.instance_of?(Regexp)
assert regexp !~ string, message(msg)
end
def assert_not_equal(expected, actual, msg = nil)
msg = message(msg) {
" expected <#{expected}> 'not' equal <#{actual}>\n\n"
}
assert expected != actual, message(msg)
end
def assert_not_nil(object, msg = nil)
msg = message(msg) {
" expected <#{object.inspect}> 'not' nil\n\n"
}
assert !object.nil?, msg
end
def assert_not_same(expected, actual, msg = nil)
msg = message(msg) {
" expected <#{expected.inspect}>\n" +
" 'not' same as <#{actual.inspect}>\n\n"
}
assert !expected.equal?(actual), msg
end
def assert_nothing_raised(msg = nil, &block)
raised = false
begin
block.call
rescue => e
raised = true
msg = message(msg) {
" expected no Exception but\n" +
" got <#{e.class}>\n\n"
}
end
assert !raised, msg
end
def assert_nothing_thrown(msg = nil, &block)
thrown = false
begin
block.call
rescue => e
raise e unless /uncaught throw `(.*)'/ =~ e.message
thrown = true
msg = message(msg) {
" expected nothing was thrown but\n" +
" got <:#{$1}>\n\n"
}
end
assert !thrown, msg
end
def flunk(reason = 'Flunked!')
assert false, message(reason)
end
def pending(reason = nil)
raise Pended, message(reason).call
end
def assertions=(val)
@_assertions = val
end
def assertions
@_assertions ||= 0
end
def message(memo = nil, &message)
lambda {
msg = SimpleTest.backtrace(caller)[0].sub(/in.*\z/, '')
msg += "\n\n"
msg += "#{message.call}" if message
msg += (memo ? " #{memo.inspect}" : ' ')
}
end
end
module Utilities
def delta_is(delta)
@@_default_delta = delta
end
def delta
@@_default_delta ||= 0.001
end
def verbose_on
@@_verbose = true
end
def verbose?
@@_verbose ||= false
end
def assert_(name, &block)
define_method "assert_#{name}", &block
end
end
class TestSuite
@@_install = false
def self.autorun
at_exit {
run
@@_install = true
} unless installed?
end
def self.installed?; @@_install end
def self.run
puts "Loaded suite #{TestCase.test_files}"
puts 'Started'
start = Time.now
messages = ''
mark = ' '
list = []
counter = {
:passed => 0,
:failed => 0,
:error => 0,
:pended => 0,
}
# TODO: this proc needs to become method
format_result = lambda {|type, msg, test_case, meth|
counter[type] += 1
count = counter.values_at(:failed, :error, :pended).inject(0, :+)
messages << format(msg) % [count, type.to_s.capitalize, test_case.class, meth]
print mark = type.to_s[0, 1].upcase
}
TestCase.test_suite.each do |test_case|
test_case = test_case.new
test_case.setup
test_case.class.test_methods.each do |meth|
start_assertion = Time.now
begin
test_case.__send__ meth
rescue Failed => msg
format_result[:failed, msg, test_case, meth]
rescue Pended => msg
format_result[:pended, msg, test_case, meth]
rescue => msg
msg = test_case.message(msg).call
format_result[:error, msg, test_case, meth]
else
print mark = '.'
end
time = Time.now - start_assertion
list << ["#{mark}) #{test_case.class}##{meth} ", time]
end
counter[:passed] += test_case.assertions
test_case.teardown
end
puts
puts test_list(list).unshift("\n") if TestCase.verbose?
puts
puts messages unless messages.empty?
puts
puts "Finished in %f seconds" % (Time.now - start)
puts
puts "%d passed, %d failed, %d errors, %d pended" %
counter.values_at(:passed, :failed, :errors, :pended)
end
def self.test_list(list)
width = list.max_by {|test, _| test.length }.first.length
list.map do |test, time|
test.ljust(width) + "(%f)" % time
end
end
def self.format(msg)
fold = msg.to_s.split("\n")[-1].length > 20
"%d)\n" +
"%s: #{msg}" +
(fold ? "\n - " : ' ') +
"in %s#%s\n\n"
end
end
class TestCase
@@_test_suite = []
@@_test_files = []
def self.method_added(meth)
if meth.to_s =~ /\Atest_/
methods = self.test_methods
warn "Warn: #{meth} has over writed\n" if methods.include? meth
methods = self.test_methods | [meth]
metaclass = class << self; self end
metaclass.__send__ :define_method, :test_methods, lambda { methods }
end
end
def self.inherited(klass)
@@_test_suite << klass
@@_test_files |= [$0]
TestSuite.autorun
end
def self.test_methods; [] end
def self.test_suite; @@_test_suite end
def self.test_files; @@_test_files end
def setup; end
def teardown; end
include Assertions
extend Utilities
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment