* See the License for the specific language governing permissions and
* limitations under the License.
*/
-/*
+/**
* @file test_runner.cpp
* @author Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
* @author Lukasz Wrzosek (l.wrzosek@samsung.com)
* @brief This file is the implementation file of test runner
*/
#include <stddef.h>
+#include <dpl/test/test_failed.h>
+#include <dpl/test/test_ignored.h>
#include <dpl/test/test_runner.h>
#include <dpl/test/test_results_collector.h>
#include <dpl/exception.h>
#include <pcrecpp.h>
#include <algorithm>
#include <cstdio>
-#include <memory.h>
-#include <libgen.h>
-#include <cstring>
-#include <cstdlib>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <string>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
}
-
namespace DPL {
namespace Test {
-namespace // anonymous
-{
-std::string BaseName(std::string aPath)
-{
- ScopedFree<char> path(strdup(aPath.c_str()));
- if (nullptr == path.Get()) {
- throw std::bad_alloc();
- }
- char* baseName = basename(path.Get());
- std::string retValue = baseName;
- return retValue;
-}
-} // namespace anonymous
-
-//! \brief Failed test message creator
-//!
-//! \param[in] aTest string for tested expression
-//! \param[in] aFile source file name
-//! \param[in] aLine source file line
-//! \param[in] aMessage error message
-TestRunner::TestFailed::TestFailed(const char* aTest,
- const char* aFile,
- int aLine,
- const std::string &aMessage)
-{
- std::ostringstream assertMsg;
- assertMsg << "[" << BaseName(aFile) << ":" << aLine
- << "] Assertion failed ("
- << aTest << ") " << aMessage;
- m_message = assertMsg.str();
-}
-TestRunner::TestFailed::TestFailed(const std::string &message)
-{
- m_message = message;
+TestResult::FailStatus TryCatch(const std::function<void(void)> &func, std::string &reason) {
+ try {
+ func();
+ } catch (const DPL::Test::TestFailed &e) {
+ reason = e.GetMessage();
+ return TestResult::FailStatus::FAILED;
+ } catch (const DPL::Test::TestIgnored &e) {
+ reason = e.GetMessage();
+ return TestResult::FailStatus::IGNORED;
+ } catch (const std::exception &e) {
+ reason = e.what();
+ return TestResult::FailStatus::FAILED;
+ } catch (...) {
+ reason = "Unknown exception";
+ return TestResult::FailStatus::FAILED;
+ }
+ reason = std::string();
+ return TestResult::FailStatus::NONE;
}
-void TestRunner::RegisterTest(const char *testName, TestCase proc)
+void TestRunner::RegisterTest(TestCasePtr testCase)
{
- m_testGroups[m_currentGroup].push_back(TestCaseStruct(testName, proc));
+ m_testGroups[m_currentGroup].push_back(testCase);
+ m_testCaseSet.insert(testCase);
}
void TestRunner::InitGroup(const char* name)
{
if(!cit->second.empty())
{
- for(TestCaseStructList::const_iterator cj = cit->second.begin(); cj != cit->second.end(); ++cj)
+ for(TestCaseList::const_iterator cj = cit->second.begin(); cj != cit->second.end(); ++cj)
{
- std::string name = cj->name;
+ std::string name = (*cj)->GetName();
std::string::size_type st = name.find('_');
if(st != std::string::npos)
{
bool TestRunner::filterByXML(std::map<std::string, bool> & casesMap)
{
for (auto &group : m_testGroups) {
- TestCaseStructList newList;
+ TestCaseList newList;
for (auto &tc : group.second)
{
- if (casesMap.find(tc.name) != casesMap.end()) {
- casesMap[tc.name] = true;
+ if (casesMap.find(tc->GetName()) != casesMap.end()) {
+ casesMap[tc->GetName()] = true;
newList.push_back(tc);
}
}
return true;
}
-TestRunner::Status TestRunner::RunTestCase(const TestCaseStruct& testCase)
+void TestRunner::RunTestCase(TestCasePtr testCase)
{
- setCurrentTestCase(&(const_cast<TestCaseStruct &>(testCase)));
- try {
- testCase.proc();
- } catch (const TestFailed &e) {
- // Simple test failure
- CollectResult(testCase.name,
- TestResult(TestResult::FailStatus::FAILED,
- getConcatedFailReason(e.GetMessage())));
-
+ setCurrentTestCase(testCase);
+
+ std::string initReason;
+ TestResult::FailStatus initStatus = TryCatch(std::bind(&TestCase::Init, testCase),
+ initReason);
+ if (initStatus != TestResult::FailStatus::NONE) {
+ CollectResult(testCase->GetName(),
+ TestResult(initStatus, getConcatedFailReason(initReason), testCase->GetPerformance()));
setCurrentTestCase(nullptr);
- return FAILED;
- } catch (const Ignored &e) {
- if (m_runIgnored) {
- // Simple test have to be implemented
- CollectResult(testCase.name,
- TestResult(TestResult::FailStatus::IGNORED, e.GetMessage()));
- }
-
- setCurrentTestCase(nullptr);
- return IGNORED;
- } catch (const std::exception &) {
- // std exception failure
- CollectResult(testCase.name,
- TestResult(TestResult::FailStatus::FAILED, "std exception"));
+ return;
+ }
- setCurrentTestCase(nullptr);
- return FAILED;
- } catch (...) {
- // Unknown exception failure
- CollectResult(testCase.name,
- TestResult(TestResult::FailStatus::FAILED, "unknown exception"));
- setCurrentTestCase(nullptr);
- return FAILED;
+ std::string testReason;
+ TestResult::FailStatus testStatus = TryCatch(std::bind(&TestCase::Test, testCase),
+ testReason);
+ testReason = getConcatedFailReason(testReason);
+ std::string finishReason;
+ TestResult::FailStatus finishStatus = TryCatch(std::bind(&TestCase::Finish, testCase),
+ finishReason);
+ finishReason = getConcatedFailReason(finishReason);
+
+ switch (finishStatus) {
+ case TestResult::FailStatus::FAILED:
+ testStatus = TestResult::FailStatus::FAILED;
+ if (!testReason.empty())
+ testReason += "\n";
+ testReason += finishReason;
+ break;
+ case TestResult::FailStatus::IGNORED:
+ if (testStatus == TestResult::FailStatus::NONE)
+ testStatus = TestResult::FailStatus::IGNORED;
+ if (!testReason.empty())
+ testReason += "\n";
+ testReason += finishReason;
+ case TestResult::FailStatus::NONE:
+ break;
+ default:
+ Assert(false && "Unhandled fail status");
}
- CollectResult(testCase.name,
- TestResult(TestResult::FailStatus::NONE,
- std::string(),
- testCase.performance));
+ CollectResult(testCase->GetName(),
+ TestResult(testStatus, testReason, testCase->GetPerformance()));
setCurrentTestCase(nullptr);
-
- // Everything OK
- return PASS;
}
void TestRunner::RunTests()
fprintf(stderr, "%sFound %d testcases...%s\n", GREEN_BEGIN, count, GREEN_END);
fprintf(stderr, "%s%s%s\n", GREEN_BEGIN, "Running tests...", GREEN_END);
for (auto &group : m_testGroups) {
- TestCaseStructList list = group.second;
+ TestCaseList list = group.second;
if (!list.empty()) {
for (auto &collector : m_collectors) {
collector.second->CollectCurrentTestGroupName(group.first);
}
list.sort();
- for (TestCaseStructList::const_iterator iterator = list.begin();
+ for (TestCaseList::const_iterator iterator = list.begin();
iterator != list.end();
++iterator)
{
- TestCaseStruct test = *iterator;
- if (m_startTestId == test.name) {
+ TestCasePtr test = *iterator;
+ if (m_startTestId == test->GetName()) {
m_startTestId = "";
}
fprintf(stderr, "%s%s%s\n\n", GREEN_BEGIN, "Finished", GREEN_END);
}
-TestRunner::TestCaseStruct *TestRunner::getCurrentTestCase()
+TestCasePtr TestRunner::getCurrentTestCase()
{
return m_currentTestCase;
}
-void TestRunner::setCurrentTestCase(TestCaseStruct* testCase)
+void TestRunner::setCurrentTestCase(TestCasePtr testCase)
{
m_currentTestCase = testCase;
}
void TestRunner::beginPerformance(std::chrono::system_clock::duration maxDurationInMicroseconds)
{
- TestCaseStruct* testCase = getCurrentTestCase();
+ TestCasePtr testCase = getCurrentTestCase();
if (!testCase)
return;
- if (!testCase->performance)
- testCase->performance.reset(new PerformanceResult(maxDurationInMicroseconds));
+ if (!testCase->GetPerformance())
+ testCase->SetPerformance(
+ std::unique_ptr<PerformanceResult> \
+ (new PerformanceResult(maxDurationInMicroseconds)));
}
void TestRunner::endPerformance()
{
- TestCaseStruct* testCase = getCurrentTestCase();
+ TestCasePtr testCase = getCurrentTestCase();
if (!testCase)
return;
- testCase->performance->Finish();
+ testCase->GetPerformance()->Finish();
}
ConstPerformanceResultPtr TestRunner::getCurrentTestCasePerformanceResult()
{
- TestCaseStruct* testCase = getCurrentTestCase();
+ TestCasePtr testCase = getCurrentTestCase();
if (!testCase)
return nullptr;
- return testCase->performance;
+ return testCase->GetPerformance();
}
void TestRunner::setCurrentTestCasePerformanceResult(const PerformanceResultPtr &performance)
{
- TestCaseStruct* testCase = getCurrentTestCase();
+ TestCasePtr testCase = getCurrentTestCase();
if (!testCase)
return;
- testCase->performance = performance;
+ testCase->SetPerformance(performance);
}
void TestRunner::addFailReason(const std::string &reason)
return reason + ret;
}
+TestRunner::~TestRunner()
+{
+ for(auto &t : m_testCaseSet)
+ delete t;
+}
+
void TestRunner::CollectResult(const std::string& id, const TestResult& result)
{
+ if (result.GetFailStatus() == TestResult::FailStatus::IGNORED && m_runIgnored)
+ return;
+
std::for_each(m_collectors.begin(),
m_collectors.end(),
[&](const TestResultsCollectors::value_type & collector)
return ExecTestRunner(args);
}
-void TestRunner::MarkAssertion()
-{
- ++m_totalAssertions;
-}
-
int TestRunner::ExecTestRunner(ArgsList args)
{
m_runIgnored = false;
arg.erase(0, startCmd.length());
for (auto &group : m_testGroups) {
for (auto &tc : group.second) {
- if (tc.name == arg) {
+ if (tc->GetName() == arg) {
m_startTestId = arg;
break;
}
TestCaseGroupMap::iterator found = m_testGroups.find(arg);
if (found != m_testGroups.end()) {
std::string name = found->first;
- TestCaseStructList newList = found->second;
+ TestCaseList newList = found->second;
m_testGroups.clear();
m_testGroups[name] = newList;
} else {
} else if (arg.find(listInGroup) == 0) {
arg.erase(0, listInGroup.length());
for (auto &test : m_testGroups[arg]) {
- printf("ID:%s\n", test.name.c_str());
+ printf("ID:%s\n", test->GetName().c_str());
}
return 0;
} else if (arg.find(allowChildLogs) == 0) {
pcrecpp::RE re(arg.c_str());
for (auto &group : m_testGroups) {
- TestCaseStructList newList;
+ TestCaseList newList;
for (auto &tc : group.second)
{
- if (re.PartialMatch(tc.name)) {
+ if (re.PartialMatch(tc->GetName())) {
newList.push_back(tc);
}
}
{
for (auto &group : m_testGroups) {
for (auto &tc : group.second) {
- printf("ID:%s:%s\n", group.first.c_str(), tc.name.c_str());
+ printf("ID:%s:%s\n", group.first.c_str(), tc->GetName().c_str());
}
}
return 0;
return 0;
}
-bool TestRunner::getRunIgnored() const
-{
- return m_runIgnored;
-}
-
void TestRunner::Terminate()
{
m_terminate = true;
return m_allowChildLogs;
}
+void TestRunner::deferFailedException(const DPL::Test::TestFailed &ex)
+{
+ if (m_deferDeepness <= 0)
+ throw ex;
+
+ if (m_deferredExceptionsMessages.empty()) {
+ m_firstDeferredFail = ex;
+ m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_FAILED;
+ }
+ m_deferredExceptionsMessages.push_back(ex.GetMessage());
+}
+
+void TestRunner::deferIgnoredException(const DPL::Test::TestIgnored &ex)
+{
+ if (m_deferDeepness <= 0)
+ throw ex;
+
+ if (m_deferredExceptionsMessages.empty()) {
+ m_firstDeferredIgnore = ex;
+ m_firstDeferredExceptionType = DeferredExceptionType::DEFERRED_IGNORED;
+ }
+ m_deferredExceptionsMessages.push_back(ex.GetMessage());
+}
+
+void TestRunner::deferBegin()
+{
+ m_deferDeepness++;
+}
+
+void TestRunner::deferEnd()
+{
+ if (m_deferDeepness > 0)
+ m_deferDeepness--;
+
+ if (m_deferDeepness > 0)
+ return;
+
+ bool oops = std::uncaught_exception();
+ size_t additionalExceptions = oops ? 0 : 1;
+ for (size_t i = additionalExceptions; i < m_deferredExceptionsMessages.size(); ++i)
+ addFailReason(m_deferredExceptionsMessages[i]);
+
+ if (!oops && !m_deferredExceptionsMessages.empty())
+ {
+ m_deferredExceptionsMessages.clear();
+ switch (m_firstDeferredExceptionType) {
+ case DeferredExceptionType::DEFERRED_FAILED:
+ throw m_firstDeferredFail;
+ case DeferredExceptionType::DEFERRED_IGNORED:
+ throw m_firstDeferredIgnore;
+ }
+ }
+ m_deferredExceptionsMessages.clear();
}
+
+} // namespace Test
} // namespace DPL