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);
}