/* This file is part of the Vc library. Copyright (C) 2009 Matthias Kretz Vc is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Vc is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Vc. If not, see . */ #ifndef UNITTEST_H #define UNITTEST_H #include #include #include #include #define runTest(name) _unit_test_global.runTestInt(&name, #name) typedef void (*testFunction)(); class _UnitTest_Global_Object { public: _UnitTest_Global_Object() : status(true), expect_failure(false), assert_failure(0), expect_assert_failure(false), float_fuzzyness( 1e-6f ), double_fuzzyness( 1e-20f ), failedTests(0), passedTests(0) { } ~_UnitTest_Global_Object() { std::cout << "\n Testing done. " << passedTests << " tests passed. " << failedTests << " tests failed." << std::endl; std::exit(failedTests); } void runTestInt(testFunction fun, const char *name); bool status; bool expect_failure; int assert_failure; bool expect_assert_failure; float float_fuzzyness; double double_fuzzyness; private: int failedTests; int passedTests; }; static _UnitTest_Global_Object _unit_test_global; void EXPECT_FAILURE() { _unit_test_global.expect_failure = true; } void _UnitTest_Global_Object::runTestInt(testFunction fun, const char *name) { _unit_test_global.status = true; _unit_test_global.expect_failure = false; fun(); if (_unit_test_global.expect_failure) { if (!_unit_test_global.status) { std::cout << "XFAIL: " << name << std::endl; } else { std::cout << "unexpected PASS: " << name << "\n This test should have failed but didn't. Check the code!" << std::endl; ++failedTests; } } else { if (!_unit_test_global.status) { std::cout << " FAIL: " << name << std::endl; ++failedTests; } else { std::cout << " PASS: " << name << std::endl; ++passedTests; } } } template static inline void setFuzzyness( T ); template<> inline void setFuzzyness( float fuzz ) { _unit_test_global.float_fuzzyness = fuzz; } template<> inline void setFuzzyness( double fuzz ) { _unit_test_global.double_fuzzyness = fuzz; } #define VERIFY(cond) if (cond) {} else { std::cout << " " << #cond << " at " << __FILE__ << ":" << __LINE__ << " failed.\n"; _unit_test_global.status = false; return; } template static inline bool unittest_compareHelper( const T1 &a, const T2 &b ) { return a == b; } template<> inline bool unittest_compareHelper( const Vc::int_v &a, const Vc::int_v &b ) { return (a == b).isFull(); } template<> inline bool unittest_compareHelper( const Vc::uint_v &a, const Vc::uint_v &b ) { return (a == b).isFull(); } template<> inline bool unittest_compareHelper( const Vc::float_v &a, const Vc::float_v &b ) { return (a == b).isFull(); } template<> inline bool unittest_compareHelper( const Vc::double_v &a, const Vc::double_v &b ) { return (a == b).isFull(); } #ifndef ENABLE_LARRABEE template<> inline bool unittest_compareHelper( const Vc::ushort_v &a, const Vc::ushort_v &b ) { return (a == b).isFull(); } template<> inline bool unittest_compareHelper( const Vc::short_v &a, const Vc::short_v &b ) { return (a == b).isFull(); } #endif template static inline bool unittest_fuzzyCompareHelper( const T &a, const T &b ) { return a == b; } template<> inline bool unittest_fuzzyCompareHelper( const float &a, const float &b ) { return a == b || std::abs(a - b) <= _unit_test_global.float_fuzzyness * std::abs(b); } template<> inline bool unittest_fuzzyCompareHelper( const Vc::float_v &a, const Vc::float_v &b ) { return a == b || Vc::abs(a - b) <= _unit_test_global.float_fuzzyness * Vc::abs(b); } #ifdef USE_SSE template<> inline bool unittest_fuzzyCompareHelper( const Vc::sfloat_v &a, const Vc::sfloat_v &b ) { return a == b || Vc::abs(a - b) <= _unit_test_global.float_fuzzyness * Vc::abs(b); } #endif template<> inline bool unittest_fuzzyCompareHelper( const double &a, const double &b ) { return a == b || std::abs(a - b) <= _unit_test_global.double_fuzzyness * std::abs(b); } template<> inline bool unittest_fuzzyCompareHelper( const Vc::double_v &a, const Vc::double_v &b ) { return a == b || Vc::abs(a - b) <= _unit_test_global.double_fuzzyness * Vc::abs(b); } template inline void unitttest_comparePrintHelper(const T1 &a, const T2 &b, const M &m, const char *aa, const char *bb, const char *file, int line, double fuzzyness = 0.) { std::cout << " " << aa << " (" << a << ") == " << bb << " (" << b << ") -> " << m; if (fuzzyness > 0.) { std::cout << " with fuzzyness " << fuzzyness; } std::cout << " at " << file << ":" << line << " failed.\n"; } template inline double unittest_fuzzynessHelper(const T &) { return 0.; } template<> inline double unittest_fuzzynessHelper(const float &) { return _unit_test_global.float_fuzzyness; } template<> inline double unittest_fuzzynessHelper(const Vc::float_v &) { return _unit_test_global.float_fuzzyness; } template<> inline double unittest_fuzzynessHelper(const double &) { return _unit_test_global.double_fuzzyness; } template<> inline double unittest_fuzzynessHelper(const Vc::double_v &) { return _unit_test_global.double_fuzzyness; } #define FUZZY_COMPARE( a, b ) \ if ( unittest_fuzzyCompareHelper( a, b ) ) {} else { \ unitttest_comparePrintHelper(a, b, (a) == (b), #a, #b, __FILE__, __LINE__, unittest_fuzzynessHelper(a)); \ _unit_test_global.status = false; \ return; \ } #define COMPARE( a, b ) \ if ( unittest_compareHelper( a, b ) ) {} else { \ unitttest_comparePrintHelper(a, b, (a) == (b), #a, #b, __FILE__, __LINE__); \ _unit_test_global.status = false; \ return; \ } static void unittest_assert(bool cond, const char *code, const char *file, int line) { if (!cond) { if (_unit_test_global.expect_assert_failure) { ++_unit_test_global.assert_failure; } else { std::cout << " " << code << " at " << file << ":" << line << " failed.\n"; std::abort(); } } } #ifdef assert #undef assert #endif #define assert(cond) unittest_assert(cond, #cond, __FILE__, __LINE__) #define EXPECT_ASSERT_FAILURE(code) \ _unit_test_global.expect_assert_failure = true; \ _unit_test_global.assert_failure = 0; \ code; \ if (_unit_test_global.assert_failure == 0) { \ /* failure expected but it didn't fail */ \ std::cout << " " << #code << " at " << __FILE__ << ":" << __LINE__ << \ " did not fail as was expected.\n"; \ _unit_test_global.status = false; \ return; \ } \ _unit_test_global.expect_assert_failure = false #endif // UNITTEST_H