From: sangwan.kwon Date: Wed, 20 Feb 2019 04:22:34 +0000 (+0900) Subject: Refactoring testbench X-Git-Tag: submit/tizen/20190430.085417~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F97%2F200197%2F3;p=platform%2Fcore%2Fsecurity%2Fklay.git Refactoring testbench - TestSuite is a set of TestCase. - TESTCASE macro generates TestCase object. Change-Id: I219ead013b3116611cf88ebee464ce095cbe45d9 Signed-off-by: sangwan.kwon --- diff --git a/include/klay/testbench.h b/include/klay/testbench.h index bc7089b..f63521a 100644 --- a/include/klay/testbench.h +++ b/include/klay/testbench.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * Copyright (c) 2019 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. @@ -17,158 +17,59 @@ #ifndef __KLAY_TESTBENCH_H__ #define __KLAY_TESTBENCH_H__ -#include +#include +#include +#include +#include #include -#include -#include #include -#include - -#include - -using namespace std::chrono; - -#define TIME_MEASURE_START auto start = system_clock::now(); -#define TIME_MEASURE_END auto end = system_clock::now(); \ - auto ms = duration_cast(end - start); \ - auto time = ms.count(); namespace klay { namespace testbench { -struct KLAY_EXPORT Source { - Source(const std::string& file, long line, const std::string& msg); - - std::string fileName; - long lineNumber; - std::string message; -}; - -class KLAY_EXPORT TestResult { -public: - TestResult(); - virtual ~TestResult(); - virtual void testsStarted(); - virtual void addFailure(const std::string& name, const Source& source); - virtual void testsEnded(); - -private: - int __failureCount; -}; - -class KLAY_EXPORT TestSuite { -public: - TestSuite(const std::string& name); - virtual ~TestSuite(); - - TestSuite(const TestSuite&) = delete; - TestSuite& operator=(const TestSuite&) = delete; - - void run(); - - const std::string& name() const { - return __testName; - } - -protected: - typedef void (TestSuite::*TestFunction)(); - - struct TestCase { - TestCase(TestFunction func, const std::string& name) : - function(func), testName(name) - { - } - - TestFunction function; - std::string testName; - }; - - virtual void setup(); - virtual void teardown(); - -#define addTest(func) \ - registerTestCase(static_cast(&func), #func) - -#define addTestWithName(func, name) \ - registerTestCase(static_cast(&func), name) - - void registerTestCase(TestFunction func, const std::string& name); - bool check(long expected, long actual, const std::string& file, long line); - -protected: - std::string __testName; - -private: - typedef std::vector TestCaseRegistry; - - TestCaseRegistry __registry; -}; - class KLAY_EXPORT Testbench { public: - static void addTestSuite(TestSuite *testSuite); static void runAllTestSuites(); - static void report(const std::string& name, const Source& source); - -private: - static Testbench& instance(); - - void add(TestSuite *testSuite); - void run(); - -private: - static std::unique_ptr collector; - - typedef std::vector TestSuiteRegistry; - TestSuiteRegistry __testSuites; }; +struct KLAY_EXPORT Source; + #ifndef __FILENAME__ -#define __FILENAME__ \ +#define __FILENAME__ \ (::strrchr(__FILE__, '/') ? ::strrchr(__FILE__, '/') + 1 : __FILE__) #endif -#define TESTCASE(TestName) \ -class TestName##TestCase : public testbench::TestSuite {\ -public: \ - TestName##TestCase() \ - : TestSuite(#TestName) \ - { \ - addTestWithName(TestName##TestCase::standalone, #TestName); \ - } \ - void standalone(); \ -} TestName##TestCase##Instance; \ -void TestName##TestCase::standalone() - -#define TEST_CHECK(condition) \ -{ \ - if (!(condition)) { \ - testbench::Testbench::report(__testName, \ - testbench::Source(__FILENAME__, __LINE__, #condition)); \ - return; \ - } \ +#define TESTCASE(TestName) \ +class TestName##TestCase final : public klay::testbench::TestCase { \ +public: \ + TestName##TestCase() : TestCase(#TestName) \ + { \ + klay::testbench::TestDriver::GetInstance().addTestCase(this); \ + } \ + void task(void) override; \ +} TestName##TestCase##Instance; \ +void TestName##TestCase::task() + +#define TEST_EXPECT(expected, actual) \ +{ \ + __typeof__(expected) exp = (expected); \ + __typeof__(actual) act = (actual); \ + if (exp != act) { \ + std::stringstream ss; \ + ss << "expected " << exp << " but it was " << act; \ + klay::testbench::TestDriver::GetInstance().addFailure(this->getName(), \ + klay::testbench::Source(__FILENAME__, __LINE__, ss.str())); \ + } \ } -#define TEST_EXPECT(expected, actual) \ -{ \ - __typeof__(expected) _exp = (expected); \ - __typeof__(actual) _act = (actual); \ - if (_exp != _act) { \ - std::stringstream _stream; \ - _stream << "expected " << _exp \ - << " but it was " << _act; \ - testbench::Testbench::report(__testName, \ - testbench::Source(__FILENAME__, __LINE__, _stream.str())); \ - } \ +#define TEST_FAIL(text) \ +{ \ + klay::testbench::TestDriver::GetInstance().addFailure(this->getName(), \ + klay::testbench::Source(__FILENAME__, __LINE__, (text))); \ + return; \ } -#define TEST_FAIL(text) \ -{ \ - testbench::Testbench::report(__testName, \ - testbench::Source(__FILENAME__, __LINE__, (text))); \ - return; \ -} } // namespace testbench } // namespace klay diff --git a/include/klay/testbench/test-case.h b/include/klay/testbench/test-case.h new file mode 100644 index 0000000..ccd98f0 --- /dev/null +++ b/include/klay/testbench/test-case.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2019 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 + */ + +#pragma once + +#include + +#include + +namespace klay { +namespace testbench { + +class KLAY_EXPORT TestCase { +public: + TestCase(const std::string& name); + virtual ~TestCase() = default; + + virtual void task(void) = 0; + + const std::string& getName(void) const noexcept; + +private: + std::string name; +}; + +} // namespace testbench +} // namespace klay diff --git a/include/klay/testbench/test-driver.h b/include/klay/testbench/test-driver.h new file mode 100644 index 0000000..b7b298d --- /dev/null +++ b/include/klay/testbench/test-driver.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2019 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 + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace klay { +namespace testbench { + +class KLAY_EXPORT TestDriver final { +public: + ~TestDriver() = default; + + TestDriver(const TestDriver &) = delete; + TestDriver(TestDriver &&) = delete; + TestDriver &operator=(const TestDriver &) = delete; + TestDriver &operator=(TestDriver &&) = delete; + + static TestDriver& GetInstance(void); + + void addTestCase(TestCase* testCase); + void addFailure(const std::string& name, const Source& source); + + void run(void); + +private: + TestDriver() = default; + + // TODO(sangwan.kwon): Support multiple TestSuite + TestSuite testSuite; + TestReporter reporter; + + static std::unique_ptr instance; + static std::once_flag flag; +}; + +} // namespace testbench +} // namespace klay diff --git a/include/klay/testbench/test-reporter.h b/include/klay/testbench/test-reporter.h new file mode 100644 index 0000000..bc74fcd --- /dev/null +++ b/include/klay/testbench/test-reporter.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2019 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 + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace klay { +namespace testbench { + +using namespace std::chrono; +using TimePoint = time_point; + +struct KLAY_EXPORT Source { + Source(const std::string& file, long line, const std::string& msg); + + std::string fileName; + long lineNumber; + std::string message; +}; + +class KLAY_EXPORT TestReporter final { +public: + TimePoint start(const std::string& name) noexcept; + void end(const std::string& name, TimePoint startPoint) noexcept; + + void addFailure(const std::string& name, const Source& source) noexcept; + void addException(const std::string& name) noexcept; + void report(void) const noexcept; + +private: + std::size_t total = 0; + std::size_t failed = 0; +}; + +} // namespace testbench +} // namespace klay diff --git a/include/klay/testbench/test-suite.h b/include/klay/testbench/test-suite.h new file mode 100644 index 0000000..eddae2f --- /dev/null +++ b/include/klay/testbench/test-suite.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2019 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 + */ + +#pragma once + +#include +#include + +#include +#include + +namespace klay { +namespace testbench { + +class KLAY_EXPORT TestSuite { +public: + TestSuite() = default; + TestSuite(const std::string& name); + virtual ~TestSuite() = default; + + void addTestCase(TestCase* testCase) noexcept; + + const std::vector& getTestCases(void) const noexcept; + + const std::string& getName(void) const noexcept; + +private: + std::vector testCases; + + std::string name; +}; + +} // namespace testbench +} // namespace klay diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 265303c..cda1dc8 100755 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,6 +22,10 @@ SET (KLAY_SOURCES ${KLAY_SRC}/error.cpp ${KLAY_SRC}/eventfd.cpp ${KLAY_SRC}/mainloop.cpp ${KLAY_SRC}/testbench.cpp + ${KLAY_SRC}/testbench/test-case.cpp + ${KLAY_SRC}/testbench/test-suite.cpp + ${KLAY_SRC}/testbench/test-driver.cpp + ${KLAY_SRC}/testbench/test-reporter.cpp ${KLAY_SRC}/file-user.cpp ${KLAY_SRC}/filesystem.cpp ${KLAY_SRC}/thread-pool.cpp diff --git a/src/testbench.cpp b/src/testbench.cpp index d4718cc..d337e2f 100644 --- a/src/testbench.cpp +++ b/src/testbench.cpp @@ -14,169 +14,14 @@ * limitations under the License */ -#include -#include - #include -#include - -using namespace console; namespace klay { namespace testbench { -Source::Source(const std::string& file, long line, const std::string& msg) : - fileName(file), lineNumber(line), message(msg) -{ -} - -TestResult::TestResult() : - __failureCount(0) -{ -} - -TestResult::~TestResult() -{ -} - -void TestResult::testsStarted() -{ -} - -void TestResult::addFailure(const std::string& name, const Source& source) -{ - std::cout << Colorize(RED) - << "\tTestcase \"" << name << "\"" - << " failed: \"" << source.message << "\"" - << " line " << source.lineNumber - << " in " << source.fileName << std::endl - << Colorize(DEFAULT); - - __failureCount++; -} - -void TestResult::testsEnded() -{ - if (__failureCount > 0) { - std::cout << Colorize(RED) - << "\nThere were " << __failureCount << " failures" << std::endl - << Colorize(DEFAULT); - } else { - std::cout << Colorize(GREEN) - << "\nThere were no test failures" << std::endl - << Colorize(DEFAULT); - } -} - -TestSuite::TestSuite(const std::string& name) - : __testName(name) -{ - Testbench::addTestSuite(this); -} - -TestSuite::~TestSuite() -{ -} - -void TestSuite::setup() -{ -} - -void TestSuite::teardown() -{ -} - -void TestSuite::run() -{ - setup(); - - TestCaseRegistry::iterator iter = __registry.begin(); - while (iter != __registry.end()) { - TestSuite::TestCase& testcase = (*iter); - - std::cout << "Entering testcase: " - << testcase.testName << std::endl; - - TIME_MEASURE_START - try { - (this->*testcase.function)(); - } catch (...) { - TEST_FAIL("\tCaught exception from " + - testcase.testName + " testcase"); - } - TIME_MEASURE_END - - std::cout << "Leaving testcase: " << testcase.testName - << " (Elapsed time: " << time - << "ms)" << std::endl; - - iter++; - } - - teardown(); -} - -void TestSuite::registerTestCase(TestFunction func, const std::string& name) -{ - __registry.push_back(TestCase(func, name)); -} - -bool TestSuite::check(long expected, long actual, const std::string& file, long line) -{ - if (expected == actual) { - return true; - } - - std::stringstream stream; - stream << "expected " << expected << " but it was " << actual; - Testbench::report(__testName, Source(file, line, stream.str())); - - return false; -} - -std::unique_ptr Testbench::collector(new TestResult()); - -void Testbench::addTestSuite(TestSuite *testSuite) -{ - instance().add(testSuite); -} - void Testbench::runAllTestSuites() { - instance().run(); -} - -Testbench& Testbench::instance() -{ - static Testbench testbench; - return testbench; -} - -void Testbench::add(TestSuite *testSuite) -{ - __testSuites.push_back(testSuite); -} - -void Testbench::report(const std::string& name, const Source& source) -{ - collector->addFailure(name, source); -} - -void Testbench::run() -{ - collector->testsStarted(); - - TestSuiteRegistry::iterator iter = __testSuites.begin(); - while (iter != __testSuites.end()) { - try { - (*iter)->run(); - } catch (...) { - // Logging exception - } - iter++; - } - - collector->testsEnded(); + TestDriver::GetInstance().run(); } } //namespace testbench diff --git a/src/testbench/test-case.cpp b/src/testbench/test-case.cpp new file mode 100644 index 0000000..6459bb8 --- /dev/null +++ b/src/testbench/test-case.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2019 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 + */ + +#include + +namespace klay { +namespace testbench { + +TestCase::TestCase(const std::string& name) : name(name) +{ +} + +const std::string& TestCase::getName(void) const noexcept +{ + return this->name; +} + +} //namespace testbench +} //namespace klay diff --git a/src/testbench/test-driver.cpp b/src/testbench/test-driver.cpp new file mode 100644 index 0000000..218d849 --- /dev/null +++ b/src/testbench/test-driver.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2019 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 + */ + +#include + +namespace klay { +namespace testbench { + +std::unique_ptr TestDriver::instance = nullptr; +std::once_flag TestDriver::flag; + +TestDriver& TestDriver::GetInstance() +{ + std::call_once(TestDriver::flag, []() { + TestDriver::instance.reset(new TestDriver); + }); + + return *TestDriver::instance; +} + +void TestDriver::addTestCase(TestCase* testCase) +{ + this->testSuite.addTestCase(testCase); +} + +void TestDriver::addFailure(const std::string& name, const Source& source) +{ + this->reporter.addFailure(name, source); +} + +void TestDriver::run(void) +{ + const auto& testCases = this->testSuite.getTestCases(); + for (const auto& tc : testCases) { + auto startTime = this->reporter.start(tc->getName()); + + try { + tc->task(); + } catch (...) { + this->reporter.addException(tc->getName()); + } + + this->reporter.end(tc->getName(), startTime); + } + + this->reporter.report(); +} + +} //namespace testbench +} //namespace klay diff --git a/src/testbench/test-reporter.cpp b/src/testbench/test-reporter.cpp new file mode 100644 index 0000000..2859053 --- /dev/null +++ b/src/testbench/test-reporter.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019 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 + */ + +#include + +namespace klay { +namespace testbench { + +Source::Source(const std::string& file, long line, const std::string& msg) + : fileName(file), lineNumber(line), message(msg) +{ +} + +TimePoint TestReporter::start(const std::string& name) noexcept +{ + std::cout << "Entering testcase: " << name << std::endl; + + this->total++; + + return system_clock::now(); +} + +void TestReporter::end(const std::string& name, TimePoint startPoint) noexcept +{ + auto endPoint = system_clock::now(); + auto ms = duration_cast(endPoint - startPoint); + auto time = ms.count(); + + std::cout << "Leaving testcase: " << name + << " (Elapsed time: " << time + << "ms)" << std::endl; +} + +void TestReporter::addFailure(const std::string& name, const Source& source) noexcept +{ + std::cout << Colorize(RED) + << "\tTestcase \"" << name << "\"" + << " failed: \"" << source.message << "\"" + << " line " << source.lineNumber + << " in " << source.fileName << std::endl + << Colorize(DEFAULT); + + this->failed++; +} + +void TestReporter::addException(const std::string& name) noexcept +{ + std::cout << Colorize(RED) + << "\tTestcase \"" << name << "\"" + << " exception occured." + << Colorize(DEFAULT); + + this->failed++; +} + +void TestReporter::report(void) const noexcept +{ + if (this->failed != 0) + std::cout << Colorize(RED) + << "\nThere were " << this->failed << " failures in total: " + << this->total << std::endl + << Colorize(DEFAULT); + else + std::cout << Colorize(GREEN) + << "\nThere were no test failures in total: " + << this->total << std::endl + << Colorize(DEFAULT); +} + +} //namespace testbench +} //namespace klay diff --git a/src/testbench/test-suite.cpp b/src/testbench/test-suite.cpp new file mode 100644 index 0000000..9658296 --- /dev/null +++ b/src/testbench/test-suite.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2019 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 + */ + +#include + +namespace klay { +namespace testbench { + +TestSuite::TestSuite(const std::string& name) : name(name) +{ +} + +void TestSuite::addTestCase(TestCase* testCase) noexcept +{ + this->testCases.push_back(testCase); +} + +const std::vector& TestSuite::getTestCases(void) const noexcept +{ + return this->testCases; +} + +const std::string& TestSuite::getName(void) const noexcept +{ + return this->name; +} + +} //namespace testbench +} //namespace klay diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 5be15de..462c5f5 100755 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -16,7 +16,7 @@ PROJECT(klay-test) SET(TEST_SRC main.cpp - rmi.cpp +# rmi.cpp auth.cpp dbus.cpp proc.cpp