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 c946fe76002223e1a767b0fd6f0e7a3516f9ea1f..83c2c05474f2af4d5ac2c3749f3dfac0715bc05c 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 ac398f0ef78fe43185624fc15f776c6ff4e77de6..0cca75454a1573023d217c0a0bc08bd2a196f2d8 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 ee1d7c345268226218a51b4e0375470e2a7bf4c0..8a14823f38f99896b527f9676eb2a17e8c97532c 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 8c52600c34c415ff2a2da985534cb617a69c6168..ea6d8c9e4b2aa405366ec6a490a1fc991eb26db7 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 279b5ef26693f2b84bf6d4f4d09e8fde6c38c65e..ac6939e3228e8917143601a6367b9c29ee0295d6 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 95e1698529e091e62a17b99c2d77feb0dd5420f4..79e96669986969a41a1a1e4b717709926dcb0e92 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 e2efb024f5e9375afd54f68b5234717dab18ff36..fcb745e7f757217b8183d8f28f342fb7df896639 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 55e889b119528c86f1fc7d5e0ceffb5a5b1a5b82..81729c57801e6db97169962fc141c929138adbde 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) {