/** @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; 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; bool getError() const; 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(new TEST_CLASS_NAME(groupName, localName)); \ \ 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 { \ 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__); \ } \ } while (false) #define EXPECT_NE(element, result) \ do { \ 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__); \ } \ } while (false) #define EXPECT_FLOAT_EQ(element, result) \ do { \ float ETEST_VARIABLE_TMP_res2 = (element) - (result); \ bool ETEST_VARIABLE_TMP_res = false; \ if (ETEST_VARIABLE_TMP_res2 < 0.00001f && ETEST_VARIABLE_TMP_res2 > -0.00001f) { \ 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__); \ } \ } while (false)