Add init and finish functionality
[platform/core/test/security-tests.git] / src / framework / src / test_runner.cpp
index 5d82330..79e9666 100644 (file)
@@ -13,7 +13,7 @@
  *    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)
@@ -21,6 +21,8 @@
  * @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>
@@ -56,49 +58,33 @@ std::string getXMLNode(xmlNodePtr node)
 
 }
 
-
 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)
@@ -136,9 +122,9 @@ bool TestRunner::filterGroupsByXmls(const std::vector<std::string> & files)
         {
             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)
                     {
@@ -222,11 +208,11 @@ bool TestRunner::filterGroupsByXmls(const std::vector<std::string> & files)
 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);
             }
         }
@@ -243,51 +229,51 @@ bool TestRunner::filterByXML(std::map<std::string, bool> & casesMap)
     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()
@@ -306,19 +292,19 @@ 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 = "";
                 }
 
@@ -344,51 +330,53 @@ void TestRunner::RunTests()
     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)
@@ -407,8 +395,17 @@ std::string TestRunner::getConcatedFailReason(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)
@@ -500,11 +497,6 @@ int TestRunner::ExecTestRunner(int argc, char *argv[])
     return ExecTestRunner(args);
 }
 
-void TestRunner::MarkAssertion()
-{
-    ++m_totalAssertions;
-}
-
 int TestRunner::ExecTestRunner(ArgsList args)
 {
     m_runIgnored = false;
@@ -542,7 +534,7 @@ int TestRunner::ExecTestRunner(ArgsList args)
             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;
                     }
@@ -563,7 +555,7 @@ int TestRunner::ExecTestRunner(ArgsList args)
             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 {
@@ -584,7 +576,7 @@ int TestRunner::ExecTestRunner(ArgsList args)
         } 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) {
@@ -628,10 +620,10 @@ int TestRunner::ExecTestRunner(ArgsList args)
 
             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);
                     }
                 }
@@ -677,7 +669,7 @@ int TestRunner::ExecTestRunner(ArgsList args)
     {
         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;
@@ -710,11 +702,6 @@ int TestRunner::ExecTestRunner(ArgsList args)
     return 0;
 }
 
-bool TestRunner::getRunIgnored() const
-{
-    return m_runIgnored;
-}
-
 void TestRunner::Terminate()
 {
     m_terminate = true;
@@ -725,5 +712,60 @@ bool TestRunner::GetAllowChildLogs()
     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