diff --git a/doxygen/lang/900_release_notes.dox.tmpl b/doxygen/lang/900_release_notes.dox.tmpl index f630c84844..f75d0b1b6f 100644 --- a/doxygen/lang/900_release_notes.dox.tmpl +++ b/doxygen/lang/900_release_notes.dox.tmpl @@ -12,6 +12,9 @@ - Util module fixes: - fixed a bug in \c get_exception_string() with Java exceptions (issue 3304) + - QUnit module fixes: + - fixed a bug where tests could not be nested + (issue 3306) @section qore_09 Qore 0.9 diff --git a/examples/test/qlib/QUnit/tests.qtest b/examples/test/qlib/QUnit/tests.qtest index a68d470437..d899a02333 100755 --- a/examples/test/qlib/QUnit/tests.qtest +++ b/examples/test/qlib/QUnit/tests.qtest @@ -38,6 +38,7 @@ public class EmptyTest inherits QUnit::Test { public class QUnitTest inherits QUnit::Test { constructor() : Test("QUnitTest", "1.0") { + addTestCase("nested test", \nestedTest()); addTestCase("issue 3172", \issue3172()); addTestCase("Dependency injection tests", \testInjectedClass()); addTestCase("Test empty test", \testEmptyTest()); @@ -51,6 +52,20 @@ public class QUnitTest inherits QUnit::Test { return True; } + nestedTest() { + { + Test test("NestedTest", "1.0"); + + code test_code = sub () { + test.assertTrue(True); + }; + test.addTestCase("my test", test_code); + test.main(); + } + + assertTrue(True); + } + issue3172() { assertThrows("TEST-SKIPPED-EXCEPTION", "fmt: 1", \testSkip(), ("fmt: %d", 1)); } diff --git a/qlib/QUnit.qm b/qlib/QUnit.qm index 00d024b130..5085c5dd9a 100644 --- a/qlib/QUnit.qm +++ b/qlib/QUnit.qm @@ -1,7 +1,7 @@ # -*- mode: qore; indent-tabs-mode: nil -*- #! @file QUnit.qm Qore user module for automatic testing -%requires qore >= 0.8.13 +%requires qore >= 0.9 %new-style %try-module xml >= 1.3 @@ -14,7 +14,7 @@ %requires Util module QUnit { - version = "0.4"; + version = "0.4.1"; desc = "User module for unit testing with dependency injection support"; author = "Zdenek Behan "; url = "http://qore.org"; @@ -130,6 +130,10 @@ public class MyTestClass inherits QUnit::DependencyInjectedTest { @section unittest_relnotes Release Notes + @subsection qunit_v0_4_1 Version 0.4.1 + - allow tests to be nested + (issue 3306) + @subsection qunit_v0_4 Version 0.4 - updated @ref QUnit::Test::testSkip() "Test::testSkip()" to use the reason argument a format string with @ref Qore::vsprintf() "vsprintf()" @@ -434,6 +438,9 @@ public class QUnit::TestCase { #! number of skipped assertions in current test case int num_asserts_skip = 0; + + #! any saved test case + auto saved_tc; } #! creates the TestCase object from the given arguments @@ -457,8 +464,7 @@ public class QUnit::TestCase { call_function_args(m_code, m_args); # Test success test.addTestResult(self, TestReporter::TEST_SUCCESS); - } - catch (hash e) { + } catch (hash e) { checkException(test, e); } } @@ -486,7 +492,7 @@ public class QUnit::TestCase { return l; } - static string getPos(hash ex) { + static string getPos(hash ex) { string pos = get_ex_pos(ex); bool qunit = (pos =~ /QUnit\.qm/); list l = TestCase::getStackList(ex.callstack, qunit); @@ -496,7 +502,7 @@ public class QUnit::TestCase { } #! handles exceptions raised while running the TestCase - checkException(QUnit::Test test, hash e) { + checkException(QUnit::Test test, hash e) { if (e.err =~ /TEST-.*EXCEPTION/) { *string assertion_name = e.arg.name; *string pos = e.arg.pos; @@ -547,11 +553,12 @@ public class QUnit::TestCase { } setupThread() { + saved_tc = remove_thread_data("tc").tc; save_thread_data("tc", self); } restoreThread() { - remove_thread_data("tc"); + save_thread_data("tc", saved_tc); } #! renames the test case @@ -976,8 +983,7 @@ addTestCase(obj); expected = sprintf("(string %y) %N", exp.encoding(), exp); actual = neg ? "" : sprintf("(string %y) %N", act.encoding(), act); } - } - catch (hash ex) { + } catch (hash ex) { } } if (!done) { @@ -1829,7 +1835,7 @@ fail("Unexpected code executed"); @return the result of the \a condition call, if the immediate value has any further use */ - public auto testAssertion(string name, code condition, *softlist args, hash expectedResultValue) { + public auto testAssertion(string name, code condition, *softlist args, hash expectedResultValue) { return testAssertion(name, condition, args, new TestResultValue(expectedResultValue)); } @@ -1842,7 +1848,7 @@ fail("Unexpected code executed"); @return the result of the \a condition call, if the immediate value has any further use */ - public auto testAssertion(string name, code condition, *softlist args, list expectedResultValue) { + public auto testAssertion(string name, code condition, *softlist args, list expectedResultValue) { return testAssertion(name, condition, args, new TestResultValue(expectedResultValue)); } @@ -1874,8 +1880,7 @@ fail("Unexpected code executed"); } else { result = new QUnit::TestResultValue(ret); } - } - catch (e) { + } catch (hash e) { if (e.err == "TEST-FAILED-EXCEPTION") { # Since boolean can contain no detail, we abuse Exceptions this way to annotate a simple failure. result = new QUnit::TestResultFailure(e.desc); @@ -1995,8 +2000,7 @@ fail("Unexpected code executed"); try { globalSetUp(); - } - catch (hash ex) { + } catch (hash ex) { gtc.checkException(self, ex); } @@ -2011,8 +2015,7 @@ fail("Unexpected code executed"); try { gtc.rename("globalTearDown"); globalTearDown(); - } - catch (hash ex) { + } catch (hash ex) { gtc.checkException(self, ex); }