From cb0c3e54fa2ed9fc04c29b98f9ea4d74fd3d6674 Mon Sep 17 00:00:00 2001 From: Marcin Niesluchowski Date: Wed, 1 Oct 2014 16:54:45 +0200 Subject: [PATCH] Add init and finish functionality 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 | 40 +++++ src/common/tests_common.h | 173 +++++++++++---------- src/framework/include/dpl/test/test_case.h | 71 +++++++++ .../include/dpl/test/test_case_extended.h | 83 ++++++++++ src/framework/include/dpl/test/test_runner.h | 70 ++++----- src/framework/include/dpl/test/test_runner_child.h | 36 +++-- .../include/dpl/test/test_runner_multiprocess.h | 38 +++-- src/framework/src/test_runner.cpp | 169 ++++++++++++-------- src/framework/src/test_runner_child.cpp | 31 ++-- src/framework/src/test_runner_multiprocess.cpp | 34 ++-- 10 files changed, 492 insertions(+), 253 deletions(-) create mode 100644 src/framework/include/dpl/test/test_case.h create mode 100644 src/framework/include/dpl/test/test_case_extended.h diff --git a/README b/README index c946fe7..83c2c05 100644 --- 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 &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(); diff --git a/src/common/tests_common.h b/src/common/tests_common.h index ac398f0..0cca754 100644 --- a/src/common/tests_common.h +++ b/src/common/tests_common.h @@ -25,12 +25,14 @@ #define _TESTS_COMMON_H_ #include +#include #include #include #include #include #include #include +#include #include #include @@ -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 index 0000000..d08d2e0 --- /dev/null +++ b/src/framework/include/dpl/test/test_case.h @@ -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 + +#include + +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 index 0000000..129365a --- /dev/null +++ b/src/framework/include/dpl/test/test_case_extended.h @@ -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 +#include +#include +#include + +#include + +namespace DPL { +namespace Test { +namespace Operations { + +template +void init(T &t, const std::string &testName) { + (void) t; + (void) testName; +} + +template +void finish(T &t) { + (void) t; +} + +template +void init(T &t, const std::string &testName) { + std::get(t).init(testName); + init(t, testName); +} + +template +void finish(T &t) { + std::get(t).finish(); + finish(t); +} + +} // namespace Operations + +template +class TestCaseExtended + : public TestCase +{ +public: + TestCaseExtended(const std::string &name, + const std::function &t)> &testFunc) + : TestCase(name), m_testFunc(testFunc) {} + +private: + virtual void Init() { Operations::init<0, std::tuple, Args...>(m_tuple, GetName()); } + virtual void Finish() { Operations::finish, Args...>(m_tuple); } + virtual void Test() { m_testFunc(m_tuple); } + + std::tuple m_tuple; + std::function &t)> m_testFunc; +}; + +} // namespace Test +} // namespace DPL + +#endif // DPL_TEST_CASE_EXTENDED_H diff --git a/src/framework/include/dpl/test/test_runner.h b/src/framework/include/dpl/test/test_runner.h index ee1d7c3..8a14823 100644 --- a/src/framework/include/dpl/test/test_runner.h +++ b/src/framework/include/dpl/test/test_runner.h @@ -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 #include #include +#include #include #include #include @@ -43,6 +45,8 @@ #include #include #include +#include +#include #include #include #include @@ -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 TestCaseStructList; - typedef std::map TestCaseGroupMap; + typedef std::list TestCaseList; + typedef std::map TestCaseGroupMap; + typedef std::set 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 & 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 ArgsList; int ExecTestRunner(ArgsList args); @@ -164,6 +149,9 @@ private: }; typedef DPL::Singleton TestRunnerSingleton; + +TestResult::FailStatus TryCatch(const std::function &func, std::string &reason); + } } // namespace DPL @@ -176,16 +164,16 @@ typedef DPL::Singleton 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 diff --git a/src/framework/include/dpl/test/test_runner_child.h b/src/framework/include/dpl/test/test_runner_child.h index 8c52600..ea6d8c9 100644 --- a/src/framework/include/dpl/test/test_runner_child.h +++ b/src/framework/include/dpl/test/test_runner_child.h @@ -16,12 +16,19 @@ /* * @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 +#include +#include + +#include +#include #include namespace DPL { @@ -74,22 +81,23 @@ class PipeWrapper : DPL::Noncopyable int m_pipefd[2]; }; -void RunChildProc(TestRunner::TestCase procChild); +void RunChildProc(const std::function &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 diff --git a/src/framework/include/dpl/test/test_runner_multiprocess.h b/src/framework/include/dpl/test/test_runner_multiprocess.h index 279b5ef..ac6939e 100644 --- a/src/framework/include/dpl/test/test_runner_multiprocess.h +++ b/src/framework/include/dpl/test/test_runner_multiprocess.h @@ -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. @@ -22,6 +22,13 @@ #ifndef DPL_TEST_RUNNER_MULTIPROCESS_H #define DPL_TEST_RUNNER_MULTIPROCESS_H +#include +#include +#include +#include +#include + +#include #include 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& 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 diff --git a/src/framework/src/test_runner.cpp b/src/framework/src/test_runner.cpp index 95e1698..79e9666 100644 --- a/src/framework/src/test_runner.cpp +++ b/src/framework/src/test_runner.cpp @@ -32,7 +32,10 @@ #include #include #include -#include +#include +#include +#include +#include #include #include @@ -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 &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 & 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 & files) bool TestRunner::filterByXML(std::map & 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 & casesMap) return true; } -void TestRunner::RunTestCase(const TestCaseStruct& testCase) +void TestRunner::RunTestCase(TestCasePtr testCase) { - setCurrentTestCase(&(const_cast(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 \ + (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; diff --git a/src/framework/src/test_runner_child.cpp b/src/framework/src/test_runner_child.cpp index e2efb02..fcb745e 100644 --- a/src/framework/src/test_runner_child.cpp +++ b/src/framework/src/test_runner_child.cpp @@ -20,6 +20,7 @@ * @brief This file is the implementation file of test runner */ #include +#include #include #include #include @@ -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 &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) { diff --git a/src/framework/src/test_runner_multiprocess.cpp b/src/framework/src/test_runner_multiprocess.cpp index 55e889b..81729c5 100644 --- a/src/framework/src/test_runner_multiprocess.cpp +++ b/src/framework/src/test_runner_multiprocess.cpp @@ -21,6 +21,7 @@ */ #include +#include #include #include #include @@ -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 &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) { -- 2.7.4