#include "harness.h" #include #include #include #include #include #include "common/logging.h" #ifndef OVG_TEST_DATA_DIR #define OVG_TEST_DATA_DIR "tests/data" #endif namespace ovgtest { std::vector ®istry() { static std::vector cases; return cases; } Registrar::Registrar(std::string name, std::function fn) { registry().push_back(Case{std::move(name), std::move(fn)}); } void fail(const char *file, int line, const std::string &what) { const char *slash = std::strrchr(file, '/'); std::string loc = slash ? slash + 1 : file; throw Failure{loc + ":" + std::to_string(line) + ": " + what}; } void skip(const std::string &reason) { throw Skipped{reason}; } std::string data_path(const std::string &leaf) { return std::string(OVG_TEST_DATA_DIR) + "/" + leaf; } int run_all(int argc, char **argv) { const char *filter = argc > 1 ? argv[1] : nullptr; int passed = 0, failed = 0, filtered = 0, skipped = 0; for (const auto &c : registry()) { if (filter && c.name.find(filter) == std::string::npos) { ++filtered; continue; } const auto t0 = std::chrono::steady_clock::now(); try { c.fn(); const auto ms = std::chrono::duration( std::chrono::steady_clock::now() - t0) .count(); std::printf(" \033[32mPASS\033[0m %-44s %6.1fms\n", c.name.c_str(), ms); ++passed; } catch (const Skipped &s) { std::printf(" \033[33mSKIP\033[0m %-44s %s\n", c.name.c_str(), s.reason.c_str()); ++skipped; } catch (const Failure &f) { std::printf(" \033[31mFAIL\033[0m %s\n %s\n", c.name.c_str(), f.message.c_str()); ++failed; } catch (const std::exception &e) { std::printf(" \033[31mFAIL\033[0m %s\n threw: %s\n", c.name.c_str(), e.what()); ++failed; } catch (...) { std::printf(" \033[31mFAIL\033[0m %s\n threw unknown exception\n", c.name.c_str()); ++failed; } } std::printf("\n %d passed, %d failed", passed, failed); if (skipped) std::printf(", %d skipped", skipped); if (filtered) std::printf(", %d filtered out", filtered); std::printf("\n\n"); return failed == 0 ? 0 : 1; } } // namespace ovgtest int main(int argc, char **argv) { // Tests exercise error paths on purpose, so the log would be mostly noise. // OVG_TEST_LOG=debug (or any level name) turns it back on when debugging. const char *lvl = std::getenv("OVG_TEST_LOG"); ovg::log::set_level(lvl ? ovg::log::level_from_string(lvl) : ovg::log::Level::Off); return ovgtest::run_all(argc, argv); }