Paste: clay test framework
Author: | j |
Mode: | text |
Date: | Mon, 2 Aug 2010 21:31:16 |
Plain Text |
record TestStatus {
passed: UInt;
failed: UInt;
}
overload TestStatus() = TestStatus(UInt(0), UInt(0));
record TestCase[F] {
name: StringConstant;
case: F;
pending?: Bool;
}
[F] overload TestCase(name, fn:F) = TestCase[F](name, fn, false);
[F] PendingTestCase(name, fn:F) = TestCase[F](name, fn, true);
record TestSuite[TestCases] {
name: StringConstant;
testCases: TestCases;
}
alias TEST_CASE_INDENT = " ";
alias TEST_FAILURE_INDENT = TEST_CASE_INDENT + TEST_CASE_INDENT;
accumulateTestStatus(test: TestStatus, newTest: TestStatus) {
test.passed += newTest.passed;
test.failed += newTest.failed;
}
reportTest(test: TestStatus, ...prefix) {
println(...prefix, test.passed, " expectations passed; ", test.failed, " failed");
}
[TestCases] runTestSuite(suite: TestSuite[TestCases]) TestStatus {
var test = TestStatus();
println("Running test suite ", suite.name, ":");
eachValue(
lambda(case) { accumulateTestStatus(test, runTestCase(case)); },
...unpack(suite.testCases)
);
reportTest(test, TEST_CASE_INDENT, "-- ");
return test;
}
pendingMessage(pending?) {
if (pending?) {
return " (pending)";
} else {
return "";
}
}
printFailure(...xs) { println(TEST_FAILURE_INDENT, ...xs); }
[F] runTestCase(case: TestCase[F]) TestStatus {
print(TEST_CASE_INDENT, case.name, pendingMessage(case.pending?), ":");
flush(stdout);
var test = TestStatus();
case.case(test);
if (test.failed > 0) {
if (case.pending?) {
printFailure("-- pending");
test.failed = 0;
} else {
printFailure("-- FAILED");
}
} else {
if (case.pending?) {
println();
printFailure("-- FINISHED (clear pending flag)");
test.failed = 1;
} else {
println("passed");
}
}
return test;
}
passed(test) { test.passed += 1; }
failed(test) { test.failed += 1; }
// primitive assertion function
expect(test: TestStatus, fn, failReportFn) {
if (fn()) {
passed(test);
} else {
failed(test);
println();
failReportFn();
}
}
expectTrue(test: TestStatus, name, fn) {
expect(test, fn, lambda() { printFailure(name, " didn't return true"); });
}
expectFalse(test: TestStatus, name, fn) {
expect(
test,
lambda() { return not fn(); },
lambda() { printFailure(name, " didn't return false"); }
);
}
expectValues(test: TestStatus, name, fn, ...results) {
expect(
test,
lambda() { return Tuple(...fn()) == Tuple(...results); },
lambda() {
printFailure(name, " didn't return the expected values:");
printFailure(TEST_CASE_INDENT, ...weaveValues(", ", ...results));
}
);
}
expectCallDefined(test: TestStatus, Proc, ...Types) {
expect(
test,
lambda() { return CallDefined?(Proc, ...Types); },
lambda() {
printFailure(Proc, " can't be called with the expected argument types:");
printFailure(TEST_CASE_INDENT, ...weaveValues(", ", ...Types));
}
);
}
expectCallUndefined(test: TestStatus, Proc, ...Types) {
expect(
test,
lambda() { return not CallDefined?(Proc, ...Types); },
lambda() {
printFailure(Proc, " shouldn't be callable with the expected argument types:");
printFailure(TEST_CASE_INDENT, ...weaveValues(", ", ...Types));
}
);
}
testMain(...suites) {
var test = TestStatus();
eachValue(
lambda(suite) { accumulateTestStatus(test, runTestSuite(suite)); },
...suites
);
reportTest(test, "Total ");
if (test.failed > 0) {
println("TESTS FAILED");
return 1;
} else {
return 0;
}
}
///////////////////// main.clay
import test.*;
main() = testMain(
TestSuite(
"test test suite", Tuple(
TestCase("should pass", lambda(test) {
expectTrue(test, "truth", lambda() { return true; });
expectFalse(test, "falsehood", lambda() { return false; });
expectValues(test, "unity", lambda() { return 1; }, 1);
expectValues(test, "unity and trinity", lambda() { return 1, 3; }, 1, 3);
expectCallDefined(test, add, Int, Int);
expectCallUndefined(test, add, String, Int);
}),
TestCase("should fail", lambda(test) {
expectTrue(test, "truth", lambda() { return false; });
expectFalse(test, "falsehood", lambda() { return true; });
expectValues(test, "unity", lambda() { return 3; }, 1);
expectValues(test, "unity and trinity", lambda() { return 1, 2; }, 1, 3);
expectCallDefined(test, add, Int, String);
expectCallUndefined(test, add, String, String);
}),
PendingTestCase("pending should pass", lambda(test) {
expectTrue(test, "truth", lambda() { return true; });
}),
PendingTestCase("pending should fail", lambda(test) {
expectTrue(test, "truth", lambda() { return false; });
})
)
)
);
New Annotation