From 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d Mon Sep 17 00:00:00 2001 From: Jef Date: Tue, 24 Sep 2024 14:54:57 +0200 Subject: Initial community commit --- .../openmpt-trunk/test/TestToolsLib.h | 362 +++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 Src/external_dependencies/openmpt-trunk/test/TestToolsLib.h (limited to 'Src/external_dependencies/openmpt-trunk/test/TestToolsLib.h') diff --git a/Src/external_dependencies/openmpt-trunk/test/TestToolsLib.h b/Src/external_dependencies/openmpt-trunk/test/TestToolsLib.h new file mode 100644 index 00000000..913f593e --- /dev/null +++ b/Src/external_dependencies/openmpt-trunk/test/TestToolsLib.h @@ -0,0 +1,362 @@ +/* + * 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 + +#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 +struct ToStringHelper +{ + std::string operator () (const T &x) + { + return mpt::afmt::val(x); + } +}; + +#ifdef MPT_TEST_CXX11 + +template<> +struct ToStringHelper +{ + std::string operator () (const mpt::endian &x) + { + if(x == mpt::endian::big) return "big"; + if(x == mpt::endian::little) return "little"; + return "unknown"; + } +}; + +template +struct ToStringHelper > +{ + std::string operator () (const FlagSet &x) + { + return mpt::afmt::val(x.GetRaw()); + } +}; + +template +struct ToStringHelper > +{ + std::string operator () (const enum_value_type &x) + { + return mpt::afmt::val(x.as_bits()); + } +}; + +template +struct ToStringHelper > +{ + std::string operator () (const std::pair &x) + { + return std::string("{") + mpt::afmt::val(x.first) + std::string(",") + mpt::afmt::val(x.second) + std::string("}"); + } +}; + +template +struct ToStringHelper > +{ + std::string operator () (const FPInt &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 +{ + 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 + inline bool IsEqual(const Tx &x, const Ty &y, std::false_type, std::false_type) + { + return (x == y); + } + + template + inline bool IsEqual(const Tx &x, const Ty &y, std::false_type, std::true_type) + { + return (x == y); + } + + template + inline bool IsEqual(const Tx &x, const Ty &y, std::true_type, std::false_type) + { + return (x == y); + } + + template + 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(y)) && (static_cast(x) == y)); + } + + template + 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 + MPT_NOINLINE void TypeCompareHelper(const Tx &x, const Ty &y) + { + if(!IsEqual(x, y, std::is_integral(), std::is_integral())) + { + throw TestFailed(MPT_AFORMAT("{} != {}")(ToStringHelper()(x), ToStringHelper()(y))); + //throw TestFailed(); + } + } + + template + MPT_NOINLINE void TypeCompareHelper(const Tx &x, const Ty &y, const Teps &eps) + { + if(!IsEqualEpsilon(x, y, eps)) + { + throw TestFailed(MPT_AFORMAT("{} != {}")(ToStringHelper()(x), ToStringHelper()(y))); + //throw TestFailed(); + } + } + +public: + + template + 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 + 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 + MPT_NOINLINE void operator () (const Tx &x, const Ty &y) + { + ShowStart(); + try + { + if(!IsEqual(x, y, std::is_integral(), std::is_integral())) + { + //throw TestFailed(MPT_AFORMAT("{} != {}")(x, y)); + throw TestFailed(); + } + ReportPassed(); + } catch(...) + { + ReportFailed(); + } + } + + template + 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 -- cgit