#include #include #include #include #include #include #include #ifndef MIGRAPHX_GUARD_TEST_TEST_HPP #define MIGRAPHX_GUARD_TEST_TEST_HPP namespace test { // NOLINTNEXTLINE #define TEST_FOREACH_OPERATOR(m) \ m(==, equal) m(!=, not_equal) m(<=, less_than_equal) m(>=, greater_than_equal) m(<, less_than) \ m(>, greater_than) // NOLINTNEXTLINE #define TEST_EACH_OPERATOR_OBJECT(op, name) \ struct name \ { \ static std::string as_string() { return #op; } \ template \ static decltype(auto) call(T&& x, U&& y) \ { \ return x op y; \ } \ }; TEST_FOREACH_OPERATOR(TEST_EACH_OPERATOR_OBJECT) inline std::ostream& operator<<(std::ostream& s, std::nullptr_t) { s << "nullptr"; return s; } template struct expression { T lhs; U rhs; friend std::ostream& operator<<(std::ostream& s, const expression& self) { s << " [ " << self.lhs << " " << Operator::as_string() << " " << self.rhs << " ]"; return s; } decltype(auto) value() const { return Operator::call(lhs, rhs); }; }; // TODO: Remove rvalue references template expression make_expression(T&& rhs, U&& lhs, Operator) { return {std::forward(rhs), std::forward(lhs)}; } template struct lhs_expression; // TODO: Remove rvalue reference template lhs_expression make_lhs_expression(T&& lhs) { return lhs_expression{std::forward(lhs)}; } template struct lhs_expression { T lhs; explicit lhs_expression(T e) : lhs(e) {} friend std::ostream& operator<<(std::ostream& s, const lhs_expression& self) { s << self.lhs; return s; } T value() const { return lhs; } // NOLINTNEXTLINE #define TEST_LHS_OPERATOR(op, name) \ template \ auto operator op(const U& rhs) const \ { \ return make_expression(lhs, rhs, name{}); /* NOLINT */ \ } TEST_FOREACH_OPERATOR(TEST_LHS_OPERATOR) // NOLINTNEXTLINE #define TEST_LHS_REOPERATOR(op) \ template \ auto operator op(const U& rhs) const \ { \ return make_lhs_expression(lhs op rhs); \ } TEST_LHS_REOPERATOR(+) TEST_LHS_REOPERATOR(-) TEST_LHS_REOPERATOR(*) TEST_LHS_REOPERATOR(/) TEST_LHS_REOPERATOR(%) TEST_LHS_REOPERATOR(&) TEST_LHS_REOPERATOR(|) TEST_LHS_REOPERATOR(&&) TEST_LHS_REOPERATOR(||) }; struct capture { template auto operator->*(const T& x) { return make_lhs_expression(x); } }; template void failed(T x, const char* msg, const char* func, const char* file, int line, F f) { if(!x.value()) { std::cout << func << std::endl; std::cout << file << ":" << line << ":" << std::endl; std::cout << " FAILED: " << msg << " " << x << std::endl; f(); } } template bool throws(F f) { try { f(); return false; } catch(...) { return true; } } template bool throws(F f, const std::string& msg = "") { try { f(); return false; } catch(const Exception& ex) { return std::string(ex.what()).find(msg) != std::string::npos; } } using string_map = std::unordered_map>; template string_map parse(std::vector as, Keyword keyword) { string_map result; std::string flag; for(auto&& x : as) { auto f = keyword(x); if(f.empty()) { result[flag].push_back(x); } else { flag = f.front(); result[flag]; // Ensure the flag exists } } return result; } inline auto& get_test_cases() { static std::vector>> cases; return cases; } inline void add_test_case(std::string name, std::function f) { get_test_cases().emplace_back(std::move(name), std::move(f)); } struct auto_register { template auto_register(const char* name, F f) noexcept { add_test_case(name, f); } }; inline void run_test_case(const std::string& name, const std::function& f) { std::cout << "[ RUN ] " << name << std::endl; f(); std::cout << "[ COMPLETE ] " << name << std::endl; } inline void run(int argc, const char* argv[]) { std::vector as(argv + 1, argv + argc); auto args = parse(as, [](auto &&) -> std::vector { return {}; }); auto cases = args[""]; if(cases.empty()) { for(auto&& tc : get_test_cases()) run_test_case(tc.first, tc.second); } else { std::unordered_map> m(get_test_cases().begin(), get_test_cases().end()); for(auto&& name : cases) run_test_case(name, m[name]); } } } // namespace test // NOLINTNEXTLINE #define CHECK(...) \ test::failed( \ test::capture{}->*__VA_ARGS__, #__VA_ARGS__, __PRETTY_FUNCTION__, __FILE__, __LINE__, [] { \ }) // NOLINTNEXTLINE #define EXPECT(...) \ test::failed(test::capture{}->*__VA_ARGS__, \ #__VA_ARGS__, \ __PRETTY_FUNCTION__, \ __FILE__, \ __LINE__, \ &std::abort) // NOLINTNEXTLINE #define STATUS(...) EXPECT((__VA_ARGS__) == 0) // NOLINTNEXTLINE #define TEST_CAT(x, ...) TEST_PRIMITIVE_CAT(x, __VA_ARGS__) // NOLINTNEXTLINE #define TEST_PRIMITIVE_CAT(x, ...) x##__VA_ARGS__ // NOLINTNEXTLINE #define TEST_CASE_REGISTER(...) \ static test::auto_register TEST_CAT(register_test_case_, __LINE__) = \ test::auto_register(#__VA_ARGS__, &__VA_ARGS__); // NOLINTNEXTLINE #define TEST_CASE(...) \ void __VA_ARGS__(); \ TEST_CASE_REGISTER(__VA_ARGS__) \ void __VA_ARGS__() #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wglobal-constructors" #endif #endif