From ce569204d26cd29174b31409b132908eccfb854f Mon Sep 17 00:00:00 2001 From: light7734 Date: Mon, 2 Feb 2026 13:56:25 +0330 Subject: [PATCH] feat(test): major qol improvements --- modules/test/entrypoint.cpp | 1 + modules/test/expects.cppm | 104 +++++++++++++++++------------------- modules/test/registry.cppm | 81 ++++++++++++++++++---------- modules/test/test.cppm | 35 +++++++++--- modules/test/test.test.cpp | 9 +++- 5 files changed, 137 insertions(+), 93 deletions(-) diff --git a/modules/test/entrypoint.cpp b/modules/test/entrypoint.cpp index 0265d33..ddb4a4a 100644 --- a/modules/test/entrypoint.cpp +++ b/modules/test/entrypoint.cpp @@ -49,6 +49,7 @@ void print_help() auto main(i32 argc, char **argv) -> i32 try { + lt::log::set_min_severity(lt::log::Level::test); auto raw_arguments = std::span(argv, argc); auto options = lt::test::Registry::Options {}; diff --git a/modules/test/expects.cppm b/modules/test/expects.cppm index 4a6b485..2a751ec 100644 --- a/modules/test/expects.cppm +++ b/modules/test/expects.cppm @@ -24,8 +24,7 @@ export void expect_unreachable( { throw std::runtime_error { std::format( - "Failed unreachable expectation:\n" - "\tlocation: {}:{}", + "unreachable reached: {}:{}", source_location.file_name(), source_location.line() ), @@ -48,12 +47,7 @@ export constexpr void expect_throw( } throw std::runtime_error { - std::format( - "Failed throwing expectation:\n" - "\tlocation: {}:{}", - source_location.file_name(), - source_location.line() - ), + std::format("did not throw: {}:{}", source_location.file_name(), source_location.line()), }; } @@ -69,10 +63,7 @@ export constexpr void expect_eq( { throw std::runtime_error { std::format( - "Failed equality expectation:\n" - "\tactual: {}\n" - "\texpected: {}\n" - "\tlocation: {}:{}", + "expect_eq: {} == {} @ {}:{}", std::to_underlying(lhs), std::to_underlying(rhs), source_location.file_name(), @@ -85,10 +76,7 @@ export constexpr void expect_eq( { throw std::runtime_error { std::format( - "Failed equality expectation:\n" - "\tactual: {}\n" - "\texpected: {}\n" - "\tlocation: {}:{}", + "expect_eq: {} == {} @ {}:{}", lhs, rhs, source_location.file_name(), @@ -108,10 +96,47 @@ export constexpr void expect_ne( { throw std::runtime_error { std::format( - "Failed un-equality expectation:\n" - "\tactual: {}\n" - "\texpected: {}\n" - "\tlocation: {}:{}", + "expect_ne: {} != {} @ {}:{}", + lhs, + rhs, + source_location.file_name(), + source_location.line() + ), + }; + } +} + +export constexpr void expect_le( + Testable auto lhs, + Testable auto rhs, + std::source_location source_location = std::source_location::current() +) +{ + if (lhs > rhs) + { + throw std::runtime_error { + std::format( + "expect_le: {} <= {} @ {}:{}", + lhs, + rhs, + source_location.file_name(), + source_location.line() + ), + }; + } +} + +export constexpr void expect_ge( + Testable auto lhs, + Testable auto rhs, + std::source_location source_location = std::source_location::current() +) +{ + if (lhs < rhs) + { + throw std::runtime_error { + std::format( + "expect_ge: {} >= {} @ {}:{}", lhs, rhs, source_location.file_name(), @@ -130,10 +155,7 @@ export constexpr void expect_true( { throw std::runtime_error { std::format( - "Failed true expectation:\n" - "\tactual: {}\n" - "\texpected: true\n" - "\tlocation: {}:{}", + "expect_true: {} @ {}:{}", expression, source_location.file_name(), source_location.line() @@ -151,10 +173,7 @@ export constexpr void expect_false( { throw std::runtime_error { std::format( - "Failed false expectation:\n" - "\tactual: {}\n" - "\texpected: true\n" - "\tlocation: {}:{}", + "expect_false: {} @ {}:{}", expression, source_location.file_name(), source_location.line() @@ -172,34 +191,7 @@ export constexpr void expect_not_nullptr( { throw std::runtime_error { std::format( - "Failed true expectation:\n" - "\tactual: nullptr\n" - "\texpected: not nullptr\n" - "\tlocation: {}:{}", - source_location.file_name(), - source_location.line() - ), - }; - } -} - - -export constexpr void expect_le( - Testable auto lhs, - Testable auto rhs, - std::source_location source_location = std::source_location::current() -) -{ - if (lhs > rhs) - { - throw std::runtime_error { - std::format( - "Failed false expectation:\n" - "\tactual: {}\n" - "\texpected: >= {}\n" - "\tlocation: {}:{}", - lhs, - rhs, + "expect_not_nullptr: @ {}:{}", source_location.file_name(), source_location.line() ), diff --git a/modules/test/registry.cppm b/modules/test/registry.cppm index a730ce0..1a9b85b 100644 --- a/modules/test/registry.cppm +++ b/modules/test/registry.cppm @@ -1,5 +1,6 @@ export module test.registry; +import logger; import preliminary; import test.expects; @@ -204,17 +205,17 @@ namespace lt::test { ++instance().m_failed_case_count; } -[[nodiscard]] /* static */ auto Registry::should_return_on_failure() -> bool +/* static */ [[nodiscard]] auto Registry::should_return_on_failure() -> bool { return instance().m_options.stop_on_fail; } -[[nodiscard]] /* static */ auto Registry::get_options() -> const Options & +/* static */ [[nodiscard]] auto Registry::get_options() -> const Options & { return instance().m_options; } -[[nodiscard]] /* static */ auto Registry::get_case_regex() -> const std::regex & +/* static */ [[nodiscard]] auto Registry::get_case_regex() -> const std::regex & { return instance().m_case_regex; } @@ -231,6 +232,30 @@ auto Registry::run_all_impl() -> i32 { if (std::regex_search(name, regex)) { + auto padding_left = std::string {}; + padding_left.resize((79 - std::strlen(name)) / 2u - 1u); + for (auto &ch : padding_left) + { + ch = '-'; + } + + auto padding_right = std::string {}; + padding_right.resize((79 - std::strlen(name)) / 2u); + if (std::strlen(name) % 2 == 0) + { + padding_right.resize(padding_right.size() + 1); + } + for (auto &ch : padding_right) + { + ch = '-'; + } + + log::test( + "\033[1;33m*{}{}{}-*\033[0m", + std::string { padding_left }, + std::string_view { name }, + std::string { padding_right } + ); suite(); increment_matched_suite_count(); } @@ -245,12 +270,12 @@ auto Registry::run_all_impl() -> i32 { if (m_options.stop_on_fail) { - std::println("Quitting due to options.stop_on_fail == true"); + log::info("Quitting due to options.stop_on_fail == true"); break; } - std::println("Uncaught exception when running suite:"); - std::println("\twhat: {}", exp.what()); + log::test("Uncaught exception when running suite:"); + log::test("\twhat: {}", exp.what()); break; } } @@ -259,32 +284,32 @@ auto Registry::run_all_impl() -> i32 { case ExecutionPolicy::normal: { - std::println("[-------STATS------]"); + // log::test("[-------STATS------]"); + // + // log::test("suites:"); + // log::test("\ttotal: {}", (i32)m_total_suite_count); + // log::test("\tpassed: {}", (i32)m_passed_suite_count); + // log::test("\tfailed: {}", (i32)m_failed_suite_count); + // log::test("\tmatched: {}", (i32)m_matched_suite_count); + // log::test("\tskipped: {}", (i32)m_skipped_suite_count); + // + // log::test("tests:"); + // log::test("\ttotal: {}", (i32)m_total_case_count); + // log::test("\tpassed: {}", (i32)m_passed_case_count); + // log::test("\tfailed: {}", (i32)m_failed_case_count); + // log::test("\tmatched: {}", (i32)m_matched_case_count); + // log::test("\tskipped: {}", (i32)m_skipped_case_count); - std::println("suites:"); - std::println("\ttotal: {}", m_total_suite_count); - std::println("\tpassed: {}", m_passed_suite_count); - std::println("\tfailed: {}", m_failed_suite_count); - std::println("\tmatched: {}", m_matched_suite_count); - std::println("\tskipped: {}", m_skipped_suite_count); - - std::println("tests:"); - std::println("\ttotal: {}", m_total_case_count); - std::println("\tpassed: {}", m_passed_case_count); - std::println("\tfailed: {}", m_failed_case_count); - std::println("\tmatched: {}", m_matched_case_count); - std::println("\tskipped: {}", m_skipped_case_count); - - std::println("________________________________________________________________"); + // log::test("________________________________________________________________"); return m_failed_case_count; } case ExecutionPolicy::stats: { - std::println("[-------STATS------]"); - std::println("Total suite count: {}", m_total_suite_count); - std::println("Total test count: {}", m_total_case_count); - std::println("________________________________________________________________"); + log::test("[-------STATS------]"); + log::test("Total suite count: {}", (i32)m_total_suite_count); + log::test("Total test count: {}", (i32)m_total_case_count); + log::test("________________________________________________________________"); return 0; } @@ -295,12 +320,12 @@ auto Registry::run_all_impl() -> i32 void Registry::print_options() { - std::println("stop-on-failure: {}", m_options.stop_on_fail); + // log::info("stop-on-failure: {}", static_cast(m_options.stop_on_fail)); } Registry::Registry() { - std::println("________________________________________________________________"); + // log::info("________________________________________________________________"); } [[nodiscard]] /* static */ auto Registry::instance() -> Registry & diff --git a/modules/test/test.cppm b/modules/test/test.cppm index aa75372..834dcfd 100644 --- a/modules/test/test.cppm +++ b/modules/test/test.cppm @@ -3,6 +3,8 @@ export module test.test; import test.expects; import test.registry; import preliminary; +import logger; + /////////////////////////////////////// // ----------* INTERFACE *--------- // @@ -12,7 +14,7 @@ namespace lt::test { class TestCase { public: - TestCase(std::string_view name); + TestCase(std::string name); // NOLINTNEXTLINE(misc-unconventional-assign-operator) auto operator=(std::invocable auto test) const -> void; @@ -21,7 +23,7 @@ private: void run_normal(std::invocable auto test) const; private: - std::string_view m_name; + std::string m_name; }; struct TestSuite @@ -68,16 +70,26 @@ void TestCase::run_normal(std::invocable auto test) const } Registry::increment_matched_case_count(); - std::println("[Running-----------] --> "); - std::println("{}", m_name); + auto padding = std::string {}; + padding.resize(79 - m_name.size()); + for (auto &ch : padding) + { + ch = ' '; + } + try { test(); } catch (const std::exception &exp) { - std::println("{}", exp.what()); - std::println("[-----------FAIL !!]"); + log::test( + "\033[1;31m{}{} | {}\033[0m", + std::string_view { m_name }, + std::string { padding }, + std::string { exp.what() } + ); + Registry::increment_failed_case_count(); if (Registry::should_return_on_failure()) @@ -89,7 +101,9 @@ void TestCase::run_normal(std::invocable auto test) const } Registry::increment_passed_case_count(); - std::println("[--------SUCCESS :D]"); + + + log::test("{}{} | \033[1;32mpass\033[0m", std::string_view { m_name }, std::string { padding }); } TestSuite::TestSuite(auto body) @@ -123,8 +137,13 @@ auto operator""_suite(const char *name, size_t size) -> TestSuite module :private; namespace lt::test { -TestCase::TestCase(std::string_view name): m_name(name) +TestCase::TestCase(std::string name): m_name(name) { + if (m_name.size() > 79u) + { + m_name.resize(79u - 3); + m_name.append("..."); + } } } // namespace lt::test diff --git a/modules/test/test.test.cpp b/modules/test/test.test.cpp index a755761..6c95038 100644 --- a/modules/test/test.test.cpp +++ b/modules/test/test.test.cpp @@ -1,7 +1,14 @@ import test; Suite expects = "expects"_suite = []() { - Case { "" } = [] { + // should be truncated... + Case { "berryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy " + "long name" } + = [] { + }; + + Case { "this emptiness machine" } = [] { + expect_le(9, 6); }; Case { "expect_unreachable" } = [] {