Add init and finish functionality 90/29090/20
authorMarcin Niesluchowski <m.niesluchow@samsung.com>
Wed, 1 Oct 2014 14:54:45 +0000 (16:54 +0200)
committerRadoslaw Bartosiak <r.bartosiak@samsung.com>
Fri, 24 Apr 2015 16:49:48 +0000 (18:49 +0200)
Classes with init() and finish() methods may be passed as additional
arguments to test macros. Those classes are passed in tuple
accessible as an argument optionalArgsTuple of test case function.
See README for usage of new macros.

Change-Id: I8c25c1bb015e89298030ea7fa223f53aeacbec11

README
src/common/tests_common.h
src/framework/include/dpl/test/test_case.h [new file with mode: 0644]
src/framework/include/dpl/test/test_case_extended.h [new file with mode: 0644]
src/framework/include/dpl/test/test_runner.h
src/framework/include/dpl/test/test_runner_child.h
src/framework/include/dpl/test/test_runner_multiprocess.h
src/framework/src/test_runner.cpp
src/framework/src/test_runner_child.cpp
src/framework/src/test_runner_multiprocess.cpp

diff --git a/README b/README
index c946fe7..83c2c05 100644 (file)
--- a/README
+++ b/README
@@ -84,6 +84,22 @@ dpl-test-framework
 Adding/removing those macro calls will add/remove test cases they provide. To
 change tests, change body of those macro calls. Registered tests are run within
 group alphabetically.
+Those macros allow additional arguments which are classes with mandatory
+methods:
+* (constructor) ()
+    Called while registering test.
+    Should not throw any exceptions
+* init(const std::string &testName)
+    Called before test case function in order of classes passed to macro.
+    Should not be forked.
+    testName argument is name of the test (first macro argument).
+* finish(void)
+    called after test case function in reversed order of classes passed to
+    macro.
+    Should not be forked.
+Created instances of those classes may be accessed from within test case body
+as argument of test case funtion is
+  std::tuple<ClassesPassed> &optionalArgsTuple
 
 dpl-test-framework
   test_runner.h
@@ -231,6 +247,30 @@ RUNNER_CHILD_TEST_NOSMACK(bar_file2_dropped_root)
                             "Wrong errno on opening " << " file");
 }
 
+class Env
+{
+public:
+    Env() { ... }
+    void init(const std::string &testName) { ... }
+    void finish() { ... }
+    void doEnv() { ... }
+};
+
+class Restore
+{
+public:
+    Restore() { ... }
+    void init(const std::string &testName) { ... }
+    void finish() { ... }
+    void doRestore() { ... }
+};
+
+RUNNER_TEST(bar_optional_args, Env, Restore)
+{
+    std::get<0>(optionalArgsTuple).doEnv();
+    std::get<1>(optionalArgsTuple).doRestore();
+}
+
 int main(int argc, char *argv[])
 {
     SummaryCollector::Register();
index ac398f0..0cca754 100644 (file)
 #define _TESTS_COMMON_H_
 
 #include <sys/smack.h>
+#include <dpl/test/test_case_extended.h>
 #include <dpl/test/test_runner.h>
 #include <dpl/test/test_runner_child.h>
 #include <dpl/test/test_runner_multiprocess.h>
 #include <privilege-control.h>
 #include <sys/smack.h>
 #include <string>
+#include <tuple>
 #include <errno.h>
 #include <string.h>
 
@@ -53,89 +55,94 @@ void creatSafe(const std::string &path, mode_t mode);
 void symlinkSafe(const std::string &targetPath, const std::string &linkPath);
 void removeDir(const std::string &path);
 
-#define RUNNER_TEST_SMACK(Proc)                                                     \
-    void Proc();                                                                    \
-    static int Static##Proc##Init()                                                 \
-    {                                                                               \
-        if(smack_check())                                                           \
-            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);  \
-                                                                                    \
-        return 0;                                                                   \
-    }                                                                               \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();              \
-    void Proc()
-
-#define RUNNER_TEST_NOSMACK(Proc)                                                   \
-    void Proc();                                                                    \
-    static int Static##Proc##Init()                                                 \
-    {                                                                               \
-        if(!(smack_check()))                                                        \
-            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);  \
-                                                                                    \
-        return 0;                                                                   \
-    }                                                                               \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();              \
-    void Proc()
-
-#define RUNNER_CHILD_TEST_SMACK(Proc)                                                \
-    void Proc();                                                                     \
-    void Proc##Child();                                                              \
-    static int Static##Proc##Init()                                                  \
-    {                                                                                \
-        if(smack_check())                                                            \
-            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);   \
-        return 0;                                                                    \
-    }                                                                                \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();               \
-    void Proc(){                                                                     \
-            DPL::Test::RunChildProc(&Proc##Child);                                   \
-    }                                                                                \
-    void Proc##Child()
-
-#define RUNNER_CHILD_TEST_NOSMACK(Proc)                                              \
-    void Proc();                                                                     \
-    void Proc##Child();                                                              \
-    static int Static##Proc##Init()                                                  \
-    {                                                                                \
-        if(!(smack_check()))                                                         \
-            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);   \
-        return 0;                                                                    \
-    }                                                                                \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();               \
-    void Proc(){                                                                     \
-            DPL::Test::RunChildProc(&Proc##Child);                                   \
-    }                                                                                \
-    void Proc##Child()
-
-#define RUNNER_MULTIPROCESS_TEST_SMACK(Proc)                                         \
-    void Proc();                                                                     \
-    void Proc##Multi();                                                              \
-    static int Static##Proc##Init()                                                  \
-    {                                                                                \
-        if(smack_check())                                                            \
-            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);   \
-        return 0;                                                                    \
-    }                                                                                \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();               \
-    void Proc(){                                                                     \
-            DPL::Test::RunMultiProc(&Proc##Multi);                                   \
-    }                                                                                \
-    void Proc##Multi()
-
-#define RUNNER_MULTIPROCESS_TEST_NOSMACK(Proc)                                       \
-    void Proc();                                                                     \
-    void Proc##Multi();                                                              \
-    static int Static##Proc##Init()                                                  \
-    {                                                                                \
-        if(!(smack_check()))                                                         \
-            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);   \
-        return 0;                                                                    \
-    }                                                                                \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();               \
-    void Proc(){                                                                     \
-            DPL::Test::RunMultiProc(&Proc##Multi);                                   \
-    }                                                                                \
-    void Proc##Multi()
+
+#define RUNNER_TEST_SMACK(Proc, ...)                                                        \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                                  \
+    static int Static##Proc##Init()                                                         \
+    {                                                                                       \
+        if (smack_check())                                                                  \
+            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+                new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                           \
+    }                                                                                       \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
+
+#define RUNNER_TEST_NOSMACK(Proc, ...)                                                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                                  \
+    static int Static##Proc##Init()                                                         \
+    {                                                                                       \
+        if (!smack_check())                                                                 \
+            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+                new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                           \
+    }                                                                                       \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
+
+#define RUNNER_CHILD_TEST_SMACK(Proc, ...)                                                  \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                                  \
+    void Proc##Child(std::tuple<__VA_ARGS__> &optionalArgsTuple);                           \
+    static int Static##Proc##Init()                                                         \
+    {                                                                                       \
+        if (smack_check())                                                                  \
+            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+                new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                           \
+    }                                                                                       \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple) {                                 \
+        DPL::Test::RunChildProc(std::bind(Proc##Child, optionalArgsTuple));                 \
+    }                                                                                       \
+    void Proc##Child(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
+
+#define RUNNER_CHILD_TEST_NOSMACK(Proc, ...)                                                \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                                  \
+    void Proc##Child(std::tuple<__VA_ARGS__> &optionalArgsTuple);                           \
+    static int Static##Proc##Init()                                                         \
+    {                                                                                       \
+        if (!smack_check())                                                                 \
+            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+                new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                           \
+    }                                                                                       \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple) {                                 \
+        DPL::Test::RunChildProc(std::bind(Proc##Child, optionalArgsTuple));                 \
+    }                                                                                       \
+    void Proc##Child(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
+
+#define RUNNER_MULTIPROCESS_TEST_SMACK(Proc, ...)                                           \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                                  \
+    void Proc##Multi(std::tuple<__VA_ARGS__> &optionalArgsTuple);                           \
+    static int Static##Proc##Init()                                                         \
+    {                                                                                       \
+        if (smack_check())                                                                  \
+            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+                new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                           \
+    }                                                                                       \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple) {                                 \
+        DPL::Test::RunMultiProc(std::bind(Proc##Multi, optionalArgsTuple));                 \
+    }                                                                                       \
+    void Proc##Multi(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
+
+#define RUNNER_MULTIPROCESS_TEST_NOSMACK(Proc, ...)                                         \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                                  \
+    void Proc##Multi(std::tuple<__VA_ARGS__> &optionalArgsTuple);                           \
+    static int Static##Proc##Init()                                                         \
+    {                                                                                       \
+        if (!smack_check())                                                                 \
+            DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+                new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                           \
+    }                                                                                       \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                      \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple) {                                 \
+        DPL::Test::RunMultiProc(std::bind(Proc##Multi, optionalArgsTuple));                 \
+    }                                                                                       \
+    void Proc##Multi(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
 
 namespace DB {
 
diff --git a/src/framework/include/dpl/test/test_case.h b/src/framework/include/dpl/test/test_case.h
new file mode 100644 (file)
index 0000000..d08d2e0
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        test_case.h
+ * @author      Marcin Niesluchowski (m.niesluchow@samsung.com)
+ * @version     1.0
+ * @brief       This file is the header file of TestCase class
+ */
+
+#ifndef DPL_TEST_CASE_H
+#define DPL_TEST_CASE_H
+
+#include <string>
+
+#include <dpl/test/performance_result.h>
+
+namespace DPL {
+namespace Test {
+
+class TestCase
+{
+public:
+    TestCase(const std::string &name)
+        : m_name(name) {}
+    virtual ~TestCase() {}
+
+    bool operator <(const TestCase &other) const {
+        return m_name < other.m_name;
+    }
+    bool operator ==(const TestCase &other) const {
+        return m_name == other.m_name;
+    }
+
+    const std::string& GetName() const {
+        return m_name;
+    }
+    PerformanceResultPtr GetPerformance() const {
+        return m_performance;
+    }
+    void SetPerformance(PerformanceResultPtr performance) {
+        m_performance = performance;
+    }
+
+    virtual void Test() = 0;
+    virtual void Init() = 0;
+    virtual void Finish() = 0;
+
+private:
+    std::string m_name;
+    PerformanceResultPtr m_performance;
+};
+
+typedef TestCase* TestCasePtr;
+
+} // namespace Test
+} // namespace DPL
+
+#endif // DPL_TEST_CASE_H
diff --git a/src/framework/include/dpl/test/test_case_extended.h b/src/framework/include/dpl/test/test_case_extended.h
new file mode 100644 (file)
index 0000000..129365a
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+/*
+ * @file        test_case_extended.h
+ * @author      Marcin Niesluchowski (m.niesluchow@samsung.com)
+ * @version     1.0
+ * @brief       This file is the header file of TestCaseExtended class
+ */
+
+#ifndef DPL_TEST_CASE_EXTENDED_H
+#define DPL_TEST_CASE_EXTENDED_H
+
+#include <cstddef>
+#include <functional>
+#include <string>
+#include <tuple>
+
+#include <dpl/test/test_case.h>
+
+namespace DPL {
+namespace Test {
+namespace Operations {
+
+template<size_t N, class T>
+void init(T &t, const std::string &testName) {
+    (void) t;
+    (void) testName;
+}
+
+template<size_t N, class T>
+void finish(T &t) {
+    (void) t;
+}
+
+template<size_t N, class T, typename First, typename ...Rest>
+void init(T &t, const std::string &testName) {
+    std::get<N>(t).init(testName);
+    init<N+1, T, Rest...>(t, testName);
+}
+
+template<size_t N, class T, typename First, typename ...Rest>
+void finish(T &t) {
+    std::get<N>(t).finish();
+    finish<N-1, T, Rest...>(t);
+}
+
+} // namespace Operations
+
+template<typename ...Args>
+class TestCaseExtended
+    : public TestCase
+{
+public:
+    TestCaseExtended(const std::string &name,
+                     const std::function<void(std::tuple<Args...> &t)> &testFunc)
+        : TestCase(name), m_testFunc(testFunc) {}
+
+private:
+    virtual void Init() { Operations::init<0, std::tuple<Args...>, Args...>(m_tuple, GetName()); }
+    virtual void Finish() { Operations::finish<sizeof...(Args)-1, std::tuple<Args...>, Args...>(m_tuple); }
+    virtual void Test() { m_testFunc(m_tuple); }
+
+    std::tuple<Args...> m_tuple;
+    std::function<void(std::tuple<Args...> &t)> m_testFunc;
+};
+
+} // namespace Test
+} // namespace DPL
+
+#endif // DPL_TEST_CASE_EXTENDED_H
index ee1d7c3..8a14823 100644 (file)
@@ -17,6 +17,7 @@
  * @file        test_runner.h
  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
  * @author      Lukasz Wrzosek (l.wrzosek@samsung.com)
+ * @author      Marcin Niesluchowski (m.niesluchow@samsung.com)
  * @version     1.0
  * @brief       This file is the header file of test runner
  */
@@ -28,6 +29,7 @@
 #include <cstdlib>
 #include <cstring>
 #include <exception>
+#include <functional>
 #include <iostream>
 #include <list>
 #include <map>
@@ -43,6 +45,8 @@
 #include <dpl/gdbbacktrace.h>
 #include <dpl/singleton.h>
 #include <dpl/test/performance_result.h>
+#include <dpl/test/test_case.h>
+#include <dpl/test/test_case_extended.h>
 #include <dpl/test/test_exception.h>
 #include <dpl/test/test_failed.h>
 #include <dpl/test/test_ignored.h>
@@ -78,36 +82,18 @@ class TestRunner
 
     void addFailReason(const std::string &reason);
 
-    typedef void (*TestCase)();
+    ~TestRunner();
 
   private:
-    struct TestCaseStruct
-    {
-        std::string name;
-        TestCase proc;
-        PerformanceResultPtr performance;
-
-        bool operator <(const TestCaseStruct &other) const
-        {
-            return name < other.name;
-        }
-
-        bool operator ==(const TestCaseStruct &other) const
-        {
-            return name == other.name;
-        }
-
-        TestCaseStruct(const std::string &n, TestCase p) :
-            name(n),
-            proc(p)
-        {}
-    };
-
-    typedef std::list<TestCaseStruct> TestCaseStructList;
-    typedef std::map<std::string, TestCaseStructList> TestCaseGroupMap;
+    typedef std::list<TestCasePtr> TestCaseList;
+    typedef std::map<std::string, TestCaseList> TestCaseGroupMap;
+    typedef std::set<TestCasePtr> TestCaseSet;
+
     TestCaseGroupMap m_testGroups;
+    TestCaseSet m_testCaseSet;
+
+    TestCasePtr m_currentTestCase;
 
-    TestCaseStruct * m_currentTestCase;
 
     std::string m_currentGroup;
 
@@ -125,10 +111,10 @@ class TestRunner
     bool filterByXML(std::map<std::string, bool> & casesMap);
     void normalizeXMLTag(std::string& str, const std::string& testcase);
 
-    void RunTestCase(const TestCaseStruct& testCase);
+    void RunTestCase(TestCasePtr testCase);
 
-    void setCurrentTestCase(TestCaseStruct* testCase);
-    TestCaseStruct *getCurrentTestCase();
+    void setCurrentTestCase(TestCasePtr testCase);
+    TestCasePtr getCurrentTestCase();
 
     void RunTests();
 
@@ -137,9 +123,8 @@ class TestRunner
     void CollectResult(const std::string& id, const TestResult &result);
 
   public:
-    void RegisterTest(const char *testName, TestCase proc);
     void InitGroup(const char* name);
-
+    void RegisterTest(TestCasePtr testCase);
     int ExecTestRunner(int argc, char *argv[]);
     typedef std::vector<std::string> ArgsList;
     int ExecTestRunner(ArgsList args);
@@ -164,6 +149,9 @@ private:
 };
 
 typedef DPL::Singleton<TestRunner> TestRunnerSingleton;
+
+TestResult::FailStatus TryCatch(const std::function<void(void)> &func, std::string &reason);
+
 }
 } // namespace DPL
 
@@ -176,16 +164,16 @@ typedef DPL::Singleton<TestRunner> TestRunnerSingleton;
     const int DPL_UNUSED Static##GroupName##InitVar =                     \
         Static##GroupName##Init();
 
-#define RUNNER_TEST(Proc)                                                      \
-    void Proc();                                                               \
-    static int Static##Proc##Init()                                            \
-    {                                                                          \
-        DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc); \
-        return 0;                                                              \
-    }                                                                          \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();         \
-    void Proc()
-
+#define RUNNER_TEST(Proc, ...)                                                          \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                              \
+    static int Static##Proc##Init()                                                     \
+    {                                                                                   \
+        DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+            new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                       \
+    }                                                                                   \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                  \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
 
 /**
  * ASSERT MACROS
index 8c52600..ea6d8c9 100644 (file)
 /*
  * @file        test_runner_child.h
  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
+ * @author      Marcin Niesluchowski (m.niesluchow@samsung.com)
  * @version     1.0
  * @brief       This file is the header file of test runner
  */
 #ifndef DPL_TEST_RUNNER_CHILD_H
 #define DPL_TEST_RUNNER_CHILD_H
 
+#include <functional>
+#include <memory>
+#include <tuple>
+
+#include <dpl/availability.h>
+#include <dpl/test/test_case_extended.h>
 #include <dpl/test/test_runner.h>
 
 namespace DPL {
@@ -74,22 +81,23 @@ class PipeWrapper : DPL::Noncopyable
     int m_pipefd[2];
 };
 
-void RunChildProc(TestRunner::TestCase procChild);
+void RunChildProc(const std::function<void(void)> &testFunc);
 } // namespace Test
 } // namespace DPL
 
-#define RUNNER_CHILD_TEST(Proc)                                                      \
-    void Proc();                                                                     \
-    void Proc##Child();                                                              \
-    static int Static##Proc##Init()                                                  \
-    {                                                                                \
-        DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);       \
-        return 0;                                                                    \
-    }                                                                                \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();               \
-    void Proc(){                                                                     \
-        DPL::Test::RunChildProc(&Proc##Child);                                       \
-    }                                                                                \
-    void Proc##Child()
+#define RUNNER_CHILD_TEST(Proc, ...)                                                    \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                              \
+    void Proc##Child(std::tuple<__VA_ARGS__> &optionalArgsTuple);                       \
+    static int Static##Proc##Init()                                                     \
+    {                                                                                   \
+        DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+            new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                       \
+    }                                                                                   \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                  \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple) {                             \
+        DPL::Test::RunChildProc(std::bind(Proc##Child, optionalArgsTuple));             \
+    }                                                                                   \
+    void Proc##Child(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
 
 #endif // DPL_TEST_RUNNER_CHILD_H
index 279b5ef..ac6939e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2014-2015 Samsung Electronics Co., Ltd All Rights Reserved
  *
  *    Licensed under the Apache License, Version 2.0 (the "License");
  *    you may not use this file except in compliance with the License.
 #ifndef DPL_TEST_RUNNER_MULTIPROCESS_H
 #define DPL_TEST_RUNNER_MULTIPROCESS_H
 
+#include <ctime>
+#include <functional>
+#include <memory>
+#include <string>
+#include <tuple>
+
+#include <dpl/availability.h>
 #include <dpl/test/test_runner_child.h>
 
 namespace DPL {
@@ -39,22 +46,23 @@ class SimplePipeWrapper :
     Status receive(std::string &data, bool &empty, time_t deadline);
 };
 
-void RunMultiProc(TestRunner::TestCase procMulti);
+void RunMultiProc(const std::function<void(void)>& testFunc);
 } // namespace Test
 } // namespace DPL
 
-#define RUNNER_MULTIPROCESS_TEST(Proc)                                               \
-    void Proc();                                                                     \
-    void Proc##Multi();                                                              \
-    static int Static##Proc##Init()                                                  \
-    {                                                                                \
-        DPL::Test::TestRunnerSingleton::Instance().RegisterTest(#Proc, &Proc);       \
-        return 0;                                                                    \
-    }                                                                                \
-    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();               \
-    void Proc(){                                                                     \
-        DPL::Test::RunMultiProc(&Proc##Multi);                                       \
-    }                                                                                \
-    void Proc##Multi()
+#define RUNNER_MULTIPROCESS_TEST(Proc, ...)                                             \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple);                              \
+    void Proc##Multi(std::tuple<__VA_ARGS__> &optionalArgsTuple);                       \
+    static int Static##Proc##Init()                                                     \
+    {                                                                                   \
+        DPL::Test::TestRunnerSingleton::Instance().RegisterTest(                        \
+            new DPL::Test::TestCaseExtended<__VA_ARGS__>(#Proc, &Proc));                \
+        return 0;                                                                       \
+    }                                                                                   \
+    const int DPL_UNUSED Static##Proc##InitVar = Static##Proc##Init();                  \
+    void Proc(std::tuple<__VA_ARGS__> &optionalArgsTuple) {                             \
+        DPL::Test::RunMultiProc(std::bind(Proc##Multi, optionalArgsTuple));             \
+    }                                                                                   \
+    void Proc##Multi(std::tuple<__VA_ARGS__> &optionalArgsTuple DPL_UNUSED)
 
 #endif // DPL_TEST_RUNNER_MULTIPROCESS_H
index 95e1698..79e9666 100644 (file)
 #include <pcrecpp.h>
 #include <algorithm>
 #include <cstdio>
-#include <memory.h>
+#include <exception>
+#include <functional>
+#include <memory>
+#include <string>
 
 #include <libxml/xpath.h>
 #include <libxml/xpathInternals.h>
@@ -55,13 +58,33 @@ std::string getXMLNode(xmlNodePtr node)
 
 }
 
-
 namespace DPL {
 namespace Test {
 
-void TestRunner::RegisterTest(const char *testName, TestCase proc)
+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(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)
@@ -99,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)
                     {
@@ -185,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);
             }
         }
@@ -206,49 +229,50 @@ bool TestRunner::filterByXML(std::map<std::string, bool> & casesMap)
     return true;
 }
 
-void TestRunner::RunTestCase(const TestCaseStruct& testCase)
+void TestRunner::RunTestCase(TestCasePtr testCase)
 {
-    setCurrentTestCase(&(const_cast<TestCaseStruct &>(testCase)));
-    m_deferDeepness = 0U;
-    try {
-        testCase.proc();
-    } catch (const TestFailed &e) {
-        // Simple test failure
-        CollectResult(testCase.name,
-                      TestResult(TestResult::FailStatus::FAILED,
-                                 getConcatedFailReason(e.GetMessage())));
-
-        setCurrentTestCase(nullptr);
-        return;
-    } catch (const TestIgnored &e) {
-        if (m_runIgnored) {
-            // Simple test have to be implemented
-            CollectResult(testCase.name,
-                          TestResult(TestResult::FailStatus::IGNORED, 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;
-    } catch (const std::exception &) {
-        // std exception failure
-        CollectResult(testCase.name,
-                      TestResult(TestResult::FailStatus::FAILED, "std exception"));
+    }
 
-        setCurrentTestCase(nullptr);
-        return;
-    } catch (...) {
-        // Unknown exception failure
-        CollectResult(testCase.name,
-                      TestResult(TestResult::FailStatus::FAILED, "unknown exception"));
-        setCurrentTestCase(nullptr);
-        return;
+    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");
     }
 
-    // Everything OK
-    CollectResult(testCase.name,
-                  TestResult(TestResult::FailStatus::NONE,
-                             std::string(),
-                             testCase.performance));
+    CollectResult(testCase->GetName(),
+                  TestResult(testStatus, testReason, testCase->GetPerformance()));
     setCurrentTestCase(nullptr);
 }
 
@@ -268,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 = "";
                 }
 
@@ -306,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)
@@ -369,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)
@@ -499,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;
                     }
@@ -520,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 {
@@ -541,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) {
@@ -585,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);
                     }
                 }
@@ -634,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;
index e2efb02..fcb745e 100644 (file)
@@ -20,6 +20,7 @@
  * @brief       This file is the implementation file of test runner
  */
 #include <stddef.h>
+#include <dpl/assert.h>
 #include <dpl/test/test_failed.h>
 #include <dpl/test/test_ignored.h>
 #include <dpl/test/test_runner.h>
@@ -287,7 +288,7 @@ PipeWrapper::Status PipeWrapper::readHelp(void *buf, int size, time_t deadline)
     return SUCCESS;
 }
 
-void RunChildProc(TestRunner::TestCase procChild)
+void RunChildProc(const std::function<void(void)> &testFunc)
 {
     PipeWrapper pipe;
     if (!pipe.isReady()) {
@@ -339,9 +340,6 @@ void RunChildProc(TestRunner::TestCase procChild)
         // End Runner after current test
         TestRunnerSingleton::Instance().Terminate();
 
-        int code = CHILD_TEST_PASS;
-        std::string msg;
-
         bool allowLogs = TestRunnerSingleton::Instance().GetAllowChildLogs();
 
         close(STDIN_FILENO);
@@ -351,17 +349,20 @@ void RunChildProc(TestRunner::TestCase procChild)
 
         pipe.setUsage(PipeWrapper::WRITEONLY);
 
-        try {
-            procChild();
-        } catch (const DPL::Test::TestFailed &e) {
-            msg = e.GetMessage();
-            code = CHILD_TEST_FAIL;
-        } catch (const DPL::Test::TestIgnored &e) {
-            msg = e.GetMessage();
-            code = CHILD_TEST_IGNORED;
-        } catch (...) { // catch all exception generated by "user" code
-            msg = "unhandled exeception";
-            code = CHILD_TEST_FAIL;
+        int code;
+        std::string msg;
+        switch (TryCatch(testFunc, msg)) {
+            case TestResult::FailStatus::FAILED:
+                code = CHILD_TEST_FAIL;
+                break;
+            case TestResult::FailStatus::IGNORED:
+                code = CHILD_TEST_IGNORED;
+                break;
+            case TestResult::FailStatus::NONE:
+                code = CHILD_TEST_PASS;
+                break;
+            default:
+                Assert(false && "Unhandled fail status");
         }
 
         if (allowLogs) {
index 55e889b..81729c5 100644 (file)
@@ -21,6 +21,7 @@
  */
 
 #include <sys/file.h>
+#include <dpl/assert.h>
 #include <dpl/exception.h>
 #include <dpl/test/test_failed.h>
 #include <dpl/test/test_ignored.h>
@@ -131,11 +132,9 @@ PipeWrapper::Status SimplePipeWrapper::receive(std::string &data, bool &empty, t
     return ERROR;
 }
 
-void RunMultiProc(TestRunner::TestCase procMulti)
+void RunMultiProc(const std::function<void(void)> &testFunc)
 {
     SimplePipeWrapper pipe;
-    int code = MULTI_TEST_PASS;
-    std::string msg = "";
     int pipeReturn;
 
     int waitStatus;
@@ -147,21 +146,20 @@ void RunMultiProc(TestRunner::TestCase procMulti)
     }
     // pipe
 
-    try {
-        procMulti();
-    } catch (const TestFailed &e) {
-        code = MULTI_TEST_FAILED;
-        msg = e.GetMessage();
-    } catch (const TestIgnored &e) {
-        code = MULTI_TEST_IGNORED;
-        msg = e.GetMessage();
-    } catch (const std::exception &) {
-        code = MULTI_TEST_FAILED;
-        msg = "std exception";
-    } catch (...) {
-        // Unknown exception failure
-        code = MULTI_TEST_FAILED;
-        msg = "unknown exception";
+    int code;
+    std::string msg;
+    switch (TryCatch(testFunc, msg)) {
+        case TestResult::FailStatus::FAILED:
+            code = MULTI_TEST_FAILED;
+            break;
+        case TestResult::FailStatus::IGNORED:
+            code = MULTI_TEST_IGNORED;
+            break;
+        case TestResult::FailStatus::NONE:
+            code = MULTI_TEST_PASS;
+            break;
+        default:
+            Assert(false && "Unhandled fail status");
     }
 
     while (true) {