//---------------------------------------------------------------------------// // ," /\ ", Azur: A game engine for CASIO fx-CG and PC // // | _/__\_ | Designed by Lephe' and the Planète Casio community. // // "._`\/'_." License: MIT // //---------------------------------------------------------------------------// // unit_check.h: Utilities for asserting and printing // // This header defines a ToString typeclass and the utility functions // runWithChecker() which extend the provided function with a Checker argument. // This object accumulates the results of tests, and stores the names and // values of the test subjects so they can be printed if any assertion fails. //--- #include #include #include #include #include template struct ToString {}; template concept to_string = requires { ToString::str; }; template requires(is_num) struct ToString { static std::string str(T x) { char s[64]; uint64_t v = (uint64_t)x.v; if constexpr (sizeof x < 8) v &= ((1ull << 8 * sizeof x) - 1); sprintf(s, "%0*lx (%lf)", 2 * (int)sizeof(x), v, (double)x); return s; } }; template<> struct ToString { static std::string str(int i) { return std::to_string(i); } }; template requires(to_string && ...) class Checker { public: Checker(): m_success(true) {} void vars(std::initializer_list names) { m_names = std::vector(names); } void values(Ts... values) { m_values = std::make_tuple(values...); } bool check(bool b, char const *expr) { if(!b) { m_success = false; fprintf(stderr, "FAILED: %s\n", expr); printValues(std::index_sequence_for {}); } return b; } bool successful() const { return m_success; } private: /* Iterate on `m_names` and `m_values` following the index sequence Is; for each index, prints the variable name and value. */ template void printValues(std::index_sequence) { (fprintf(stderr, " %s: %s\n", m_names[Is], ToString::type> ::str(std::get(m_values)).c_str()), ...); } std::vector m_names; std::tuple m_values; bool m_success; }; template requires(to_string) bool runWithChecker(std::function &)> f) { Checker c; runOnSampleInputs([f, &c](T x) { f(x, c); }); return c.successful(); } template requires(to_string && to_string) bool runWithChecker(std::function &)> f) { Checker c; runOnSampleInputs([f, &c](T x, U y) { f(x, y, c); }); return c.successful(); }