#* Very simple testing library.
To use, first:
include :assert
Then use the setup method to wrap all your tests up:
setup { }
Within the setup block you may have a series of tests.
Inside the tests, you can use assert, assert_equal, assert_false,
assert_null, and assert_match:
setup {
test "test name goes here" {
assert { 5 > 10 }
assert_equal "hello" :hello
assert_false { :cats > :dogs }
assert_null null
assert_match /\d{3}-\d{3}-\d{4}/ "378-555-1010"
}
}
Additionally, you can supply a name for the entire test suite:
setup name: "sweet tests" {
#...
}
*#
#Gathers tests and runs them
test_manager = new
#A new context for each test
test_context = new
#Create a new manager by providing a block full of tests
test_manager.init = { block, name = null |
my.tests = []
my.name = name
block
}
#Create a test
test_manager.prototype [ test: { name, block |
my.tests << test_context.new(name, ->block)
}
#Run the tests and track the results
run: {
failures = []
skips = []
total_tests = my.tests.length
num_tests = 0
num_assertions = 0
null? my.name, { p "Running tests..." } { p "Running #{my.name}..." }
my.tests.shuffle.each_with_index { t, i |
print "(#{i + 1}/#{total_tests}) #{t.name}#{' ' * (40 - t.name.length)}\r"
protect { t.run } rescue: { err |
true? err.type == "skipped_test"
{ skips << [ name: t.name, message: err.to_s ] }
{ failures << [ name: t.name, message: err.to_s ] }
}
num_tests = num_tests + 1
num_assertions = num_assertions + t.assertions
}
p
true? failures.empty?, {
p "All tests passed!"
}
{
p "Test failure(s):"
p
failures.each_with_index { f, i |
p "\t#{i + 1}. '#{f[:name]}': #{f[:message]}\n"
}
}
false? skips.empty?
{
p "Skipped test(s):"
skips.each_with_index { s, i |
p "\t#{i + 1}. '#{s[:name]}': #{s[:message]}\n"
}
}
p "#{num_tests} tests, #{num_assertions} assertions, #{skips.length} skipped, #{failures.length} failures."
[tests: num_tests, assertions: num_assertions, failures: failures.length, skips: skips.length]
}
]
#Namespace for assertions
assertions = object.new
#Check if a condition is true.
#If it isn't, show message.
assertions.assert = { condition, message = null |
false? condition, {
throw null? message
{ "Assertion failed" }
{ "Assertion failed: " << message }
}
{ true }
}
#Check that _expected_ is equal to _actual_
assertions.assert_equal = { expected, actual |
e = expected
r = actual
assert { e == r } "expected #{e}, but was #{r}"
}
#Check that _not_expected_ does not equal _actual_
assertions.assert_not_equal = { not_expected, actual |
e = not_expected
r = actual
assert { e != r } "expected #{e} to not be #{r}"
}
#Check that a condition raises an error
assertions.assert_fail = { condition |
failed = false
protect { condition } rescue: { failed = true }
assert failed
}
#Check that a condition is false
assertions.assert_false = { condition, message = null |
r = condition
null? message
{ message = "expected #{r} to be false" }
assert { false? r } message
}
#Check that a condition is null
assertions.assert_null = { condition |
r = condition
assert { null? r } "expected #{r} to be null"
}
#Check that a regular expression matches the given string
assertions.assert_match = { pattern, actual |
r = actual
assert pattern.match(r) "#{r} expected to match #{pattern}"
}
#Add all the assertions to the test context
test_context.squish assertions
#Set up a test context
test_context.init = { name, block |
my.name = name
my.tests = ->block
my.assertions = 0
}
#Runs the tests
test_context.run = { my.tests }
#Disable the p method
test_context.p = { }
#Override assert so we can count assertions
test_context.assert = { condition, message = null |
my.assertions = my.assertions + 1
false? condition, {
throw null? message, "assert failed", message
}
}
test_context.skip = { message |
throw exception.new("Skipped: #{message}", "skipped_test")
}
export assertions, "assertions"
export { block, options = [:] |
p "Loading tests..."
test_manager.new(->block, options[:name]).run }, "setup"