/** @file * @author Edouard DUPIN * @copyright 2011, Edouard DUPIN, all right reserved * @license MPL v2.0 (see license file) */ #pragma once #include #include #include #define TEST_CLASS_NAME(groupName, localName) \ groupName##_##localName##_test /* template class hasEtkStreamExporter { typedef char one; typedef long two; //template static one test( decltype(T::toString()) ); template static one test( decltype(&etk::operator<<(etk::Stream&,const T&)) ); template static two test(...); public: enum { value = sizeof(test(0)) == sizeof(char) }; }; */ template class hasMemberToString { typedef char one; typedef long two; template static one test( decltype(T::toString()) ); template static two test(...); public: enum { value = sizeof(test(0)) == sizeof(char) }; }; template struct hasEtkStreamExporter { typedef char yes[1]; typedef char no[2]; template static yes& test( U& ); template static no& test(...); static etk::Stream &s; static T const &t; static bool const value = sizeof( test( s << t ) ) == sizeof( yes ); // line 48 }; namespace has_insertion_operator_impl { typedef char no; typedef char yes[2]; struct any_t { template any_t( T const& ); }; no operator<<( etk::Stream&, any_t const& ); yes& test( etk::Stream& ); no test( no ); template struct has_insertion_operator { static etk::Stream &s; static T const &t; static bool const value = sizeof( test(s << t) ) == sizeof( yes ); }; } template struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator { }; namespace etest { template::value, int>::type = 0 > etk::String exportResultToString(const ETEST_TYPE& _element) { return "nullptr"; } template::value && has_insertion_operator::value, int>::type = 0 > etk::String exportResultToString(const ETEST_TYPE& _element) { etk::Stream tmp; tmp << _element; return tmp.str(); } template::value && !has_insertion_operator::value, int>::type = 0 > etk::String exportResultToString(const ETEST_TYPE& _element) { return "---"; } class GenericTest { private: etk::String m_file; uint32_t m_line; etk::String m_testGroup; etk::String m_testName; bool m_haveError; protected: uint32_t m_numberCheck; uint32_t m_numberCheckFail; public: GenericTest(const char* _file, uint32_t _line, const char* _testGroup, const char* _testName); virtual ~GenericTest() = default; const etk::String& getFileName() const; uint32_t getFileLine() const; const etk::String& getTestGroup() const; const etk::String& getTestName() const; /** * @brief Get if an error occured during the test * @return true an error occured, false otherwise */ bool getError() const; /** * @brief Get the number of check done in the test * @return simple count of test done */ uint32_t getNumberCheck() const; /** * @brief Get the number of check done in the test * @return simple count of test done with error */ uint32_t getNumberCheckError() const; void addCheck() { m_numberCheck++; } void testResult(bool _result, const etk::String& _test1Value, const etk::String& _test1, const etk::String& _test2Value, const etk::String& _test2, uint32_t _line); void clearLocal(); virtual void run() = 0; }; void unInit(); void init(int32_t _argc, const char *_argv[]); int32_t runAllTest(); uint32_t registerTest(etest::GenericTest* _element); extern GenericTest* g_currentTest; } #define TEST(groupName,localName) \ class TEST_CLASS_NAME(groupName, localName) : public etest::GenericTest { \ protected: \ static uint32_t registerElement; \ public: \ TEST_CLASS_NAME(groupName, localName)(): \ etest::GenericTest(__FILE__, __LINE__, #groupName, #localName) { \ \ } \ void run() override; \ }; \ \ uint32_t TEST_CLASS_NAME(groupName, localName)::registerElement = etest::registerTest(\ etk::memory::allocatorNewFull("etest_test_class", nullptr, __LINE__, __FILE__)); \ \ void TEST_CLASS_NAME(groupName, localName)::run() // This all is to be compatible with the gtest API (in main lines). #define RUN_ALL_TESTS etest::runAllTest #define EXPECT_EQ(element, result) \ do { \ etest::g_currentTest->addCheck(); \ ETEST_DEBUG(" [ SUB-RUN ] EXPECT_EQ(" << #element << ", " << #result << ");"); \ bool ETEST_VARIABLE_TMP_res = ((element) == (result)); \ if (etest::g_currentTest == nullptr) { \ ETEST_CRITICAL("Not in a test"); \ } else { \ etest::g_currentTest->testResult(ETEST_VARIABLE_TMP_res, \ etest::exportResultToString(element), \ #element, \ etest::exportResultToString(result), \ #result, \ __LINE__); \ } \ ETEST_DEBUG(" [ SUB-DONE ]"); \ } while (false) #define EXPECT_NE(element, result) \ do { \ etest::g_currentTest->addCheck(); \ ETEST_DEBUG(" [ SUB-RUN ] EXPECT_NE(" << #element << ", " << #result << ");"); \ bool ETEST_VARIABLE_TMP_res = ((element) != (result)); \ if (etest::g_currentTest == nullptr) { \ ETEST_CRITICAL("Not in a test"); \ } else { \ etest::g_currentTest->testResult(ETEST_VARIABLE_TMP_res, \ etest::exportResultToString(element), \ #element, \ etest::exportResultToString(result), \ #result, \ __LINE__); \ } \ ETEST_DEBUG(" [ SUB-DONE ]"); \ } while (false) #define ASSERT_NE(element, result) \ do { \ etest::g_currentTest->addCheck(); \ ETEST_DEBUG(" [ SUB-RUN ] ASSERT_NE(" << #element << ", " << #result << ");"); \ bool ETEST_VARIABLE_TMP_res = ((element) != (result)); \ if (etest::g_currentTest == nullptr) { \ ETEST_CRITICAL("Not in a test"); \ } else { \ etest::g_currentTest->testResult(ETEST_VARIABLE_TMP_res, \ etest::exportResultToString(element), \ #element, \ etest::exportResultToString(result), \ #result, \ __LINE__); \ } \ ETEST_DEBUG(" [ SUB-DONE ]"); \ if (ETEST_VARIABLE_TMP_res == true) { \ return; \ } \ } while (false) #define EXPECT_FLOAT_EQ_DELTA(element, result, delta) \ do { \ etest::g_currentTest->addCheck(); \ ETEST_DEBUG(" [ SUB-RUN ] EXPECT_FLOAT_EQ(" << #element << ", " << #result << ");"); \ float ETEST_VARIABLE_TMP_res2 = (element) - (result); \ bool ETEST_VARIABLE_TMP_res = false; \ if (ETEST_VARIABLE_TMP_res2 < delta && ETEST_VARIABLE_TMP_res2 > -delta) { \ ETEST_VARIABLE_TMP_res = true; \ } \ if (etest::g_currentTest == nullptr) { \ ETEST_CRITICAL("Not in a test"); \ } else { \ etest::g_currentTest->testResult(ETEST_VARIABLE_TMP_res, \ etest::exportResultToString(element), \ #element, \ etest::exportResultToString(result), \ #result, \ __LINE__); \ } \ ETEST_DEBUG(" [ SUB-DONE ]"); \ } while (false) #define EXPECT_FLOAT_EQ(element, result) \ EXPECT_FLOAT_EQ_DELTA(element, result, 0.00001f)