// eqpalg/test/test_harness.h #pragma once #include #include #include #include #include #include #include struct TestRunner { struct Case { const char* name; std::function fn; }; inline static std::vector cases; static int run() { int passed = 0, failed = 0; for (auto& c : cases) { std::cout << " " << c.name << " ... "; try { c.fn(); std::cout << "PASSED\n"; passed++; } catch (const std::exception& e) { std::cout << "FAILED\n " << e.what() << "\n"; failed++; } catch (...) { std::cout << "FAILED (unknown)\n"; failed++; } } std::cout << "\n" << passed << " passed, " << failed << " failed\n"; return failed ? 1 : 0; } }; struct AutoReg { AutoReg(const char* name, std::function fn) { TestRunner::cases.push_back({name, std::move(fn)}); } }; #define TEST(name) \ static void testfn_##name(); \ static AutoReg autoreg_##name(#name, testfn_##name); \ static void testfn_##name() #define CHECK(expr) \ do { \ if (!(expr)) \ throw std::runtime_error("CHECK(" #expr ") failed"); \ } while (0) #define CHECK_EQ(a, b) \ do { \ if ((a) != (b)) { \ std::ostringstream os; \ os << "CHECK_EQ: " << (a) << " != " << (b); \ throw std::runtime_error(os.str()); \ } \ } while (0) #define CHECK_FLOAT_EQ(a, b, eps) \ do { \ if (std::fabs((a) - (b)) > (eps)) { \ std::ostringstream os; \ os << "CHECK_FLOAT_EQ: |" << (a) << " - " << (b) << "| > " << (eps); \ throw std::runtime_error(os.str()); \ } \ } while (0) #define CHECK_THROWS(expr) \ do { \ bool caught = false; \ try { \ (void)(expr); \ } catch (...) { \ caught = true; \ } \ if (!caught) \ throw std::runtime_error("CHECK_THROWS(" #expr ") did not throw"); \ } while (0)