diff --git a/modules/beast_core/diagnostic/beast_UnitTest.cpp b/modules/beast_core/diagnostic/beast_UnitTest.cpp index f905b8adc..92c5b3291 100644 --- a/modules/beast_core/diagnostic/beast_UnitTest.cpp +++ b/modules/beast_core/diagnostic/beast_UnitTest.cpp @@ -37,6 +37,13 @@ UnitTest::~UnitTest() getAllTests().removeFirstMatchingValue (this); } +String UnitTest::getTestName() const noexcept +{ + String s; + s << m_packageName << "." << m_className; + return s; +} + String const& UnitTest::getClassName() const noexcept { return m_className; @@ -100,7 +107,7 @@ void UnitTest::beginTestCase (String const& name) finishCase (); String s; - s << m_packageName << "/" << m_className << ": " << name; + s << getTestName () << " : " << name; logMessage (s); m_case = new Case (name, m_className); @@ -231,91 +238,126 @@ bool UnitTests::anyTestsFailed () const noexcept return m_results->failures > 0; } -void UnitTests::runTests (Array const& tests) +UnitTests::TestList UnitTests::selectTests ( + String const& match, TestList const& tests) const noexcept +{ + TestList list; + list.ensureStorageAllocated (tests.size ()); + + int const indexOfDot = match.indexOfChar ('.'); + String const package = (indexOfDot == -1) ? match : match.substring (0, indexOfDot); + String const testname = (indexOfDot == -1) ? "" + : match.substring (indexOfDot + 1, match.length () + 1); + + if (package != String::empty) + { + if (testname != String::empty) + { + // "package.testname" : First test which matches + for (int i = 0; i < tests.size(); ++i) + { + UnitTest* const test = tests [i]; + if (package.equalsIgnoreCase (test->getPackageName ()) && + testname.equalsIgnoreCase (test->getClassName ())) + { + list.add (test); + break; + } + } + } + else + { + // Get all tests in the package + list = selectPackage (package, tests); + + // If no trailing slash on package, try tests + if (list.size () == 0 && indexOfDot == -1) + { + std::cout << "Trying package as test" << std::endl; + + // Try "package" as a testname + list = selectTest (package, tests); + } + } + } + else if (testname != String::empty) + { + list = selectTest (testname, tests); + } + else + { + // All non manual tests + for (int i = 0; i < tests.size(); ++i) + { + UnitTest* const test = tests [i]; + if (test->getWhen () != UnitTest::runManual) + list.add (test); + } + } + + return list; +} + +UnitTests::TestList UnitTests::selectPackage ( + String const& package, TestList const& tests) const noexcept +{ + TestList list; + list.ensureStorageAllocated (tests.size ()); + for (int i = 0; i < tests.size(); ++i) + { + UnitTest* const test = tests [i]; + if (package.equalsIgnoreCase (test->getPackageName ()) && + test->getWhen () != UnitTest::runManual) + list.add (test); + } + return list; +} + +UnitTests::TestList UnitTests::selectTest ( + String const& testname, TestList const& tests) const noexcept +{ + TestList list; + for (int i = 0; i < tests.size(); ++i) + { + UnitTest* const test = tests [i]; + if (testname.equalsIgnoreCase (test->getClassName ())) + { + list.add (test); + break; + } + } + return list; +} + +UnitTests::TestList UnitTests::selectStartupTests (TestList const& tests) const noexcept +{ + TestList list; + for (int i = 0; i < tests.size(); ++i) + { + UnitTest* const test = tests [i]; + if (test->getWhen () == UnitTest::runStartup) + list.add (test); + } + return list; +} + +void UnitTests::runSelectedTests (String const& match, TestList const& tests) +{ + runTests (selectTests (match, tests)); +} + +void UnitTests::runTests (TestList const& tests) { m_results = new Results; - for (int i = 0; i < tests.size (); ++i) { if (shouldAbortTests()) break; - runTest (*tests [i]); } - m_results->secondsElapsed = RelativeTime ( Time::getCurrentTime () - m_results->whenStarted).inSeconds (); } - -void UnitTests::runAllTests () -{ - UnitTest::TestList const& allTests (UnitTest::getAllTests ()); - - Array tests; - - tests.ensureStorageAllocated (allTests.size ()); - - for (int i = 0; i < allTests.size(); ++i) - { - UnitTest* const test = allTests [i]; - - if (test->getWhen () == UnitTest::runNormal) - { - tests.add (test); - } - } - - runTests (tests); -} - -void UnitTests::runStartupTests () -{ - UnitTest::TestList const& allTests (UnitTest::getAllTests ()); - - Array tests; - - tests.ensureStorageAllocated (allTests.size ()); - - for (int i = 0; i < allTests.size(); ++i) - { - UnitTest* const test = allTests [i]; - - if (test->getWhen () == UnitTest::runStartup) - { - tests.add (test); - } - } - - runTests (tests); -} - -void UnitTests::runTestsByName (String const& name) -{ - UnitTest::TestList const& allTests (UnitTest::getAllTests ()); - - Array tests; - - tests.ensureStorageAllocated (allTests.size ()); - - for (int i = 0; i < allTests.size(); ++i) - { - UnitTest* const test = allTests [i]; - - if (test->getPackageName () == name && - (test->getWhen () == UnitTest::runNormal || - test->getWhen () == UnitTest::runStartup)) - { - tests.add (test); - } - else if (test->getClassName () == name) - { - tests.add (test); - break; - } - } - - runTests (tests); -} void UnitTests::onFailure () { @@ -384,7 +426,7 @@ public: case UnitTest::runStartup: s << "[FORCED] "; break; }; - s << test.getPackageName () << "/" << test.getClassName (); + s << test.getTestName (); logMessage (s); } diff --git a/modules/beast_core/diagnostic/beast_UnitTest.h b/modules/beast_core/diagnostic/beast_UnitTest.h index 546bd43a6..a7ff9d291 100644 --- a/modules/beast_core/diagnostic/beast_UnitTest.h +++ b/modules/beast_core/diagnostic/beast_UnitTest.h @@ -199,6 +199,9 @@ public: /** Destructor. */ virtual ~UnitTest(); + /** Returns the fully qualified test name in the form . */ + String getTestName() const noexcept; + /** Returns the class name of the test. */ const String& getClassName() const noexcept; @@ -334,6 +337,8 @@ private: class BEAST_API UnitTests : public Uncopyable { public: + typedef UnitTest::TestList TestList; + struct Results { Results () @@ -374,21 +379,99 @@ public: //-------------------------------------------------------------------------- + /** Selects zero or more tests from specified packages or test names. + + The name can be in these formats: + "" + + "." + "." + "." + + "" + An empty string will match all tests objects which are not + marked to be run manually. + + + Selects all tests which belong to that package, excluding those + which must be run manually. If no package with that name exists, + then this will select the first test from any package which matches + the name. If the test is a manual test, it will be selected. + + "." + Selects all tests which belong to that package, excluding those + which must be run manually. If no package with that name exists, + then no tests will be selected. + + "." + Selects only the first test that matches the given testname and + package, regardless of the manual run setting. If no test with a + matching package and test name is found, then no test is selected. + + "/" + Selects the first test which matches the testname, even if it + is a manual test. + + Some examples of names: + + "beast" All unit tests in beast + "beast.File" Just the File beast unit test + ".Random" The first test with the name Random + + @note Matching is not case-sensitive. + + @param match The string used to match tests + @param tests An optional parameter containing a list of tests to match. + */ + TestList selectTests (String const& match = "", + TestList const& tests = UnitTest::getAllTests ()) const noexcept; + + /** Selects all tests which match the specified package. + + Tests marked to be run manually are not included. + + @note Matching is not case-sensitive. + + @param match The string used to match tests + @param tests An optional parameter containing a list of tests to match. + */ + TestList selectPackage (String const& package, + TestList const& tests = UnitTest::getAllTests ()) const noexcept; + + /** Selects the first test whose name matches, from any package. + + This can include tests marked to be run manually. + + @note Matching is not case-sensitive. + + @param match The name of the test to match. + @param tests An optional parameter containing a list of tests to match. + */ + TestList selectTest (String const& testname, + TestList const& tests = UnitTest::getAllTests ()) const noexcept; + + /** Selects the startup tests. + A test marked as runStartup will be forced to run on launch. + Typically these are lightweight tests that ensure the system + environment will not cause the program to exhibit undefined behavior. + + @param tests An optional parameter containing a list of tests to match. + */ + TestList selectStartupTests (TestList const& tests = UnitTest::getAllTests ()) const noexcept; + + /** Run a list of matching tests. + This first calls selectTests and then runTeests on the resulting list. + @param match The string used for matching. + @param tests An optional parameter containing a list of tests to match. + */ + void runSelectedTests (String const& match = "", + TestList const& tests = UnitTest::getAllTests ()); + /** Runs the specified list of tests. - This is used internally and won't normally need to be called. + @note The tests are run regardless of the run settings. + @param tests The list of tests to run. */ - void runTests (Array const& tests); - - /** Runs all the UnitTest objects that currently exist. - This calls @ref runTests for all the objects listed in @ref UnitTest::getAllTests. - */ - void runAllTests (); - - /** Runs the startup tests. */ - void runStartupTests (); - - /** Run a particular test or group. */ - void runTestsByName (String const& name); + void runTests (TestList const& tests); protected: friend class UnitTest; diff --git a/modules/beast_core/misc/beast_Main.cpp b/modules/beast_core/misc/beast_Main.cpp index 2286286ef..029e480b2 100644 --- a/modules/beast_core/misc/beast_Main.cpp +++ b/modules/beast_core/misc/beast_Main.cpp @@ -99,7 +99,7 @@ void Main::runStartupUnitTests () StartupUnitTests tests; - tests.runStartupTests (); + tests.runTests (tests.selectStartupTests ()); if (tests.anyTestsFailed ()) {