123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362 |
- /*
- * TestToolsLib.h
- * --------------
- * Purpose: Unit test framework for libopenmpt.
- * Notes : This is more complex than the OpenMPT version because we cannot
- * rely on a debugger and have to deal with exceptions ourselves.
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #pragma once
- #include "openmpt/all/BuildSettings.hpp"
- #ifdef ENABLE_TESTS
- #ifndef MODPLUG_TRACKER
- //#define MPT_TEST_CXX11
- #include "mpt/test/test.hpp"
- #include <type_traits>
- #include "mpt/base/bit.hpp"
- #include "openmpt/base/FlagSet.hpp"
- #include "../soundlib/Snd_defs.h"
- OPENMPT_NAMESPACE_BEGIN
- namespace Test {
- class mpt_test_reporter
- : public mpt::test::silent_reporter
- {
- public:
- mpt_test_reporter() = default;
- ~mpt_test_reporter() override = default;
- public:
- void case_run(const mpt::source_location & loc) override;
- void case_run(const mpt::source_location & loc, const char * text_e) override;
- void case_run(const mpt::source_location & loc, const char * text_ex, const char * text_e) override;
- void case_run(const mpt::source_location & loc, const char * text_a, const char * text_cmp, const char * text_b) override;
- void case_result(const mpt::source_location & loc, const mpt::test::result & result) override;
- };
- extern int fail_count;
- enum Verbosity
- {
- VerbosityQuiet,
- VerbosityNormal,
- VerbosityVerbose,
- };
- enum Fatality
- {
- FatalityContinue,
- FatalityStop
- };
- struct TestFailed
- {
- std::string values;
- TestFailed(const std::string &values) : values(values) { }
- TestFailed() { }
- };
- } // namespace Test
- template<typename T>
- struct ToStringHelper
- {
- std::string operator () (const T &x)
- {
- return mpt::afmt::val(x);
- }
- };
- #ifdef MPT_TEST_CXX11
- template<>
- struct ToStringHelper<mpt::endian>
- {
- std::string operator () (const mpt::endian &x)
- {
- if(x == mpt::endian::big) return "big";
- if(x == mpt::endian::little) return "little";
- return "unknown";
- }
- };
- template<typename enum_t, typename store_t>
- struct ToStringHelper<FlagSet<enum_t, store_t> >
- {
- std::string operator () (const FlagSet<enum_t, store_t> &x)
- {
- return mpt::afmt::val(x.GetRaw());
- }
- };
- template<typename enum_t>
- struct ToStringHelper<enum_value_type<enum_t> >
- {
- std::string operator () (const enum_value_type<enum_t> &x)
- {
- return mpt::afmt::val(x.as_bits());
- }
- };
- template<typename Ta, typename Tb>
- struct ToStringHelper<std::pair<Ta, Tb> >
- {
- std::string operator () (const std::pair<Ta, Tb> &x)
- {
- return std::string("{") + mpt::afmt::val(x.first) + std::string(",") + mpt::afmt::val(x.second) + std::string("}");
- }
- };
- template<std::size_t FRACT, typename T>
- struct ToStringHelper<FPInt<FRACT, T> >
- {
- std::string operator () (const FPInt<FRACT, T> &x)
- {
- return std::string("FPInt<") + mpt::afmt::val(FRACT) + std::string(",") + mpt::afmt::val(typeid(T).name()) + std::string(">{") + mpt::afmt::val(x.GetInt()) + std::string(".") + mpt::afmt::val(x.GetFract()) + std::string("}");
- }
- };
- template<>
- struct ToStringHelper<SamplePosition>
- {
- std::string operator () (const SamplePosition &x)
- {
- return mpt::afmt::val(x.GetInt()) + std::string(".") + std::string("0x") + mpt::afmt::hex0<8>(x.GetFract());
- }
- };
- #endif // MPT_TEST_CXX11
- namespace Test {
- class Testcase
- {
- private:
- Fatality const fatality;
- Verbosity const verbosity;
- const char * const desc;
- mpt::source_location const loc;
- public:
- Testcase(Fatality fatality, Verbosity verbosity, const char * const desc, const mpt::source_location &loc);
- public:
- std::string AsString() const;
- void ShowStart() const;
- void ShowProgress(const char * text) const;
- void ShowPass() const;
- void ShowFail(bool exception = false, const char * const text = nullptr) const;
- void ReportPassed();
- void ReportFailed();
- void ReportException();
- private:
- template <typename Tx, typename Ty>
- inline bool IsEqual(const Tx &x, const Ty &y, std::false_type, std::false_type)
- {
- return (x == y);
- }
- template <typename Tx, typename Ty>
- inline bool IsEqual(const Tx &x, const Ty &y, std::false_type, std::true_type)
- {
- return (x == y);
- }
- template <typename Tx, typename Ty>
- inline bool IsEqual(const Tx &x, const Ty &y, std::true_type, std::false_type)
- {
- return (x == y);
- }
- template <typename Tx, typename Ty>
- inline bool IsEqual(const Tx &x, const Ty &y, std::true_type /* is_integer */, std::true_type /* is_integer */ )
- {
- // Avoid signed-unsigned-comparison warnings and test equivalence in case of either type conversion direction.
- return ((x == static_cast<Tx>(y)) && (static_cast<Ty>(x) == y));
- }
- template <typename Tx, typename Ty, typename Teps>
- inline bool IsEqualEpsilon(const Tx &x, const Ty &y, const Teps &eps)
- {
- return std::abs(x - y) <= eps;
- }
- public:
- #ifdef MPT_TEST_CXX11
- private:
- template <typename Tx, typename Ty>
- MPT_NOINLINE void TypeCompareHelper(const Tx &x, const Ty &y)
- {
- if(!IsEqual(x, y, std::is_integral<Tx>(), std::is_integral<Ty>()))
- {
- throw TestFailed(MPT_AFORMAT("{} != {}")(ToStringHelper<Tx>()(x), ToStringHelper<Ty>()(y)));
- //throw TestFailed();
- }
- }
- template <typename Tx, typename Ty, typename Teps>
- MPT_NOINLINE void TypeCompareHelper(const Tx &x, const Ty &y, const Teps &eps)
- {
- if(!IsEqualEpsilon(x, y, eps))
- {
- throw TestFailed(MPT_AFORMAT("{} != {}")(ToStringHelper<Tx>()(x), ToStringHelper<Ty>()(y)));
- //throw TestFailed();
- }
- }
- public:
- template <typename Tfx, typename Tfy>
- MPT_NOINLINE void operator () (const Tfx &fx, const Tfy &fy)
- {
- ShowStart();
- try
- {
- ShowProgress("Calculate x ...");
- const auto x = fx();
- ShowProgress("Calculate y ...");
- const auto y = fy();
- ShowProgress("Compare ...");
- TypeCompareHelper(x, y);
- ReportPassed();
- } catch(...)
- {
- ReportFailed();
- }
- }
- template <typename Tfx, typename Tfy, typename Teps>
- MPT_NOINLINE void operator () (const Tfx &fx, const Tfy &fy, const Teps &eps)
- {
- ShowStart();
- try
- {
- ShowProgress("Calculate x ...");
- const auto x = fx();
- ShowProgress("Calculate y ...");
- const auto y = fy();
- ShowProgress("Compare ...");
- TypeCompareHelper(x, y, eps);
- ReportPassed();
- } catch(...)
- {
- ReportFailed();
- }
- }
- #define VERIFY_EQUAL(x,y) Test::Testcase(Test::FatalityContinue, Test::VerbosityNormal, #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;} )
- #define VERIFY_EQUAL_NONCONT(x,y) Test::Testcase(Test::FatalityStop , Test::VerbosityNormal, #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;} )
- #define VERIFY_EQUAL_QUIET_NONCONT(x,y) Test::Testcase(Test::FatalityStop , Test::VerbosityQuiet , #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;} )
- #define VERIFY_EQUAL_EPS(x,y,eps) Test::Testcase(Test::FatalityContinue, Test::VerbosityNormal, #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( [&](){return (x) ;}, [&](){return (y) ;}, (eps) )
- #else
- public:
- template <typename Tx, typename Ty>
- MPT_NOINLINE void operator () (const Tx &x, const Ty &y)
- {
- ShowStart();
- try
- {
- if(!IsEqual(x, y, std::is_integral<Tx>(), std::is_integral<Ty>()))
- {
- //throw TestFailed(MPT_AFORMAT("{} != {}")(x, y));
- throw TestFailed();
- }
- ReportPassed();
- } catch(...)
- {
- ReportFailed();
- }
- }
- template <typename Tx, typename Ty, typename Teps>
- MPT_NOINLINE void operator () (const Tx &x, const Ty &y, const Teps &eps)
- {
- ShowStart();
- try
- {
- if(!IsEqualEpsilon(x, y, eps))
- {
- //throw TestFailed(MPT_AFORMAT("{} != {}")(x, y));
- throw TestFailed();
- }
- ReportPassed();
- } catch(...)
- {
- ReportFailed();
- }
- }
- #define VERIFY_EQUAL(x,y) Test::Testcase(Test::FatalityContinue, Test::VerbosityNormal, #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( (x) , (y) )
- #define VERIFY_EQUAL_NONCONT(x,y) Test::Testcase(Test::FatalityStop , Test::VerbosityNormal, #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( (x) , (y) )
- #define VERIFY_EQUAL_QUIET_NONCONT(x,y) Test::Testcase(Test::FatalityStop , Test::VerbosityQuiet , #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( (x) , (y) )
- #define VERIFY_EQUAL_EPS(x,y,eps) Test::Testcase(Test::FatalityContinue, Test::VerbosityNormal, #x " == " #y , MPT_SOURCE_LOCATION_CURRENT() )( (x) , (y), (eps) )
- #endif
- };
- #define DO_TEST(func) \
- do { \
- Test::Testcase test(Test::FatalityStop, Test::VerbosityVerbose, #func , MPT_SOURCE_LOCATION_CURRENT() ); \
- try { \
- test.ShowStart(); \
- fail_count = 0; \
- func(); \
- if(fail_count > 0) { \
- throw Test::TestFailed(); \
- } \
- test.ReportPassed(); \
- } catch(...) { \
- test.ReportException(); \
- } \
- } while(0)
- } // namespace Test
- OPENMPT_NAMESPACE_END
- #endif // !MODPLUG_TRACKER
- #endif // ENABLE_TESTS
|