#pragma once /////////////////////////////////////////////////////////////////////// // TestUtilitiesDemo.h - facilities for single-user test harness // // ver 2.0 // // Language: C++, Visual Studio 2017 // // Application: Most Projects, CSE687 - Object Oriented Design // // Author: Jim Fawcett, Syracuse University, CST 4-187 // // jfawcett@twcny.rr.com // /////////////////////////////////////////////////////////////////////// /* * Package Operations: * ------------------- * This package provides classes: * - TestExecutor Executes single test in the context of a try-catch block * - TestExecutive Uses TestExecutor to run a sequence of tests * * Required Files: * --------------- * TestUtilities.h * * Maintenance History: * -------------------- * ver 2.0 : 28 Aug 2018 * - major change from tests defined by lambdas * to tests defined by classes derived from ITest interface * ver 1.0 : 12 Jan 2018 * - first release * - taken from Utilities/TestUtilities package * * Notes: * ------ * - Designed to provide all functionality in header file. * - Implementation file only needed for test and demo. * * Planned Additions and Changes: * ------------------------------ * - none yet */ #include #include #include #include namespace Utilities { ///////////////////////////////////////////////////////////////////// // TestExecutor class // - supports execution of callable objects for testing in the // context of a try-catch block. struct ITest { virtual bool test() = 0; virtual ~ITest() {} }; class TestExecutor { public: bool execute(std::shared_ptr pTest, const std::string& name, std::ostream& out = std::cout); private: void check(bool result, std::ostream& out); }; //----< execute tests in the context of a try-catch block >---------- bool TestExecutor::execute(std::shared_ptr pTest, const std::string& name, std::ostream& out) { bool result = false; try { result = pTest->test(); // execute test which may throw an exception check(result, out); out << " -- \"" << name << "\"\n"; } catch (std::exception& ex) { check(false, out); out << " -- \"" << name << "\" "; out << ex.what() << "\n"; } return result; } //----< display test results >--------------------------------------- void TestExecutor::check(bool result, std::ostream& out) { if (result) out << " passed"; else out << " failed"; } /////////////////////////////////////////////////////////////////////// // TestExecutive class // - executes a sequence of tests with the help of TestExecutor class TestExecutive { public: using TestItem = struct { std::shared_ptr pTest; std::string testName; }; using Tests = std::vector; bool doTests(); void registerTest(std::shared_ptr pTest, const std::string& testName); void registerTest(const TestItem& ts); private: Tests tests_; // collection of test items }; //----< store test in test collection for later execution >-------- inline void TestExecutive::registerTest(std::shared_ptr pTest, const std::string& testName) { TestItem ts{ pTest, testName }; tests_.push_back(ts); // push_back copies the test item // - that makes a new shared_ptr sharing the same test as the original // - it also makes a copy of the test name string } inline void TestExecutive::registerTest(const TestItem& ts) { tests_.push_back(ts); // push_back copies the test item // - that makes a new shared_ptr sharing the same test as the original // - it also makes a copy of the test name string } //----< execute each stored test >--------------------------------- inline bool TestExecutive::doTests() { TestExecutor tester; bool result = true; for (auto item : tests_) { bool tResult = tester.execute(item.pTest, item.testName); if (tResult == false) result = false; } return result; } }