feat(test): major qol improvements

This commit is contained in:
light7734 2026-02-02 13:56:25 +03:30
parent e30965c607
commit ce569204d2
Signed by: light7734
GPG key ID: E7CE6145374F0B5F
5 changed files with 137 additions and 93 deletions

View file

@ -49,6 +49,7 @@ void print_help()
auto main(i32 argc, char **argv) -> i32 auto main(i32 argc, char **argv) -> i32
try try
{ {
lt::log::set_min_severity(lt::log::Level::test);
auto raw_arguments = std::span<char *>(argv, argc); auto raw_arguments = std::span<char *>(argv, argc);
auto options = lt::test::Registry::Options {}; auto options = lt::test::Registry::Options {};

View file

@ -24,8 +24,7 @@ export void expect_unreachable(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed unreachable expectation:\n" "unreachable reached: {}:{}",
"\tlocation: {}:{}",
source_location.file_name(), source_location.file_name(),
source_location.line() source_location.line()
), ),
@ -48,12 +47,7 @@ export constexpr void expect_throw(
} }
throw std::runtime_error { throw std::runtime_error {
std::format( std::format("did not throw: {}:{}", source_location.file_name(), source_location.line()),
"Failed throwing expectation:\n"
"\tlocation: {}:{}",
source_location.file_name(),
source_location.line()
),
}; };
} }
@ -69,10 +63,7 @@ export constexpr void expect_eq(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed equality expectation:\n" "expect_eq: {} == {} @ {}:{}",
"\tactual: {}\n"
"\texpected: {}\n"
"\tlocation: {}:{}",
std::to_underlying<decltype(lhs)>(lhs), std::to_underlying<decltype(lhs)>(lhs),
std::to_underlying<decltype(rhs)>(rhs), std::to_underlying<decltype(rhs)>(rhs),
source_location.file_name(), source_location.file_name(),
@ -85,10 +76,7 @@ export constexpr void expect_eq(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed equality expectation:\n" "expect_eq: {} == {} @ {}:{}",
"\tactual: {}\n"
"\texpected: {}\n"
"\tlocation: {}:{}",
lhs, lhs,
rhs, rhs,
source_location.file_name(), source_location.file_name(),
@ -108,10 +96,47 @@ export constexpr void expect_ne(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed un-equality expectation:\n" "expect_ne: {} != {} @ {}:{}",
"\tactual: {}\n" lhs,
"\texpected: {}\n" rhs,
"\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(
"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, lhs,
rhs, rhs,
source_location.file_name(), source_location.file_name(),
@ -130,10 +155,7 @@ export constexpr void expect_true(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed true expectation:\n" "expect_true: {} @ {}:{}",
"\tactual: {}\n"
"\texpected: true\n"
"\tlocation: {}:{}",
expression, expression,
source_location.file_name(), source_location.file_name(),
source_location.line() source_location.line()
@ -151,10 +173,7 @@ export constexpr void expect_false(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed false expectation:\n" "expect_false: {} @ {}:{}",
"\tactual: {}\n"
"\texpected: true\n"
"\tlocation: {}:{}",
expression, expression,
source_location.file_name(), source_location.file_name(),
source_location.line() source_location.line()
@ -172,34 +191,7 @@ export constexpr void expect_not_nullptr(
{ {
throw std::runtime_error { throw std::runtime_error {
std::format( std::format(
"Failed true expectation:\n" "expect_not_nullptr: @ {}:{}",
"\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,
source_location.file_name(), source_location.file_name(),
source_location.line() source_location.line()
), ),

View file

@ -1,5 +1,6 @@
export module test.registry; export module test.registry;
import logger;
import preliminary; import preliminary;
import test.expects; import test.expects;
@ -204,17 +205,17 @@ namespace lt::test {
++instance().m_failed_case_count; ++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; 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; 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; return instance().m_case_regex;
} }
@ -231,6 +232,30 @@ auto Registry::run_all_impl() -> i32
{ {
if (std::regex_search(name, regex)) 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(); suite();
increment_matched_suite_count(); increment_matched_suite_count();
} }
@ -245,12 +270,12 @@ auto Registry::run_all_impl() -> i32
{ {
if (m_options.stop_on_fail) 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; break;
} }
std::println("Uncaught exception when running suite:"); log::test("Uncaught exception when running suite:");
std::println("\twhat: {}", exp.what()); log::test("\twhat: {}", exp.what());
break; break;
} }
} }
@ -259,32 +284,32 @@ auto Registry::run_all_impl() -> i32
{ {
case ExecutionPolicy::normal: 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:"); // log::test("________________________________________________________________");
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("________________________________________________________________");
return m_failed_case_count; return m_failed_case_count;
} }
case ExecutionPolicy::stats: case ExecutionPolicy::stats:
{ {
std::println("[-------STATS------]"); log::test("[-------STATS------]");
std::println("Total suite count: {}", m_total_suite_count); log::test("Total suite count: {}", (i32)m_total_suite_count);
std::println("Total test count: {}", m_total_case_count); log::test("Total test count: {}", (i32)m_total_case_count);
std::println("________________________________________________________________"); log::test("________________________________________________________________");
return 0; return 0;
} }
@ -295,12 +320,12 @@ auto Registry::run_all_impl() -> i32
void Registry::print_options() void Registry::print_options()
{ {
std::println("stop-on-failure: {}", m_options.stop_on_fail); // log::info("stop-on-failure: {}", static_cast<bool>(m_options.stop_on_fail));
} }
Registry::Registry() Registry::Registry()
{ {
std::println("________________________________________________________________"); // log::info("________________________________________________________________");
} }
[[nodiscard]] /* static */ auto Registry::instance() -> Registry & [[nodiscard]] /* static */ auto Registry::instance() -> Registry &

View file

@ -3,6 +3,8 @@ export module test.test;
import test.expects; import test.expects;
import test.registry; import test.registry;
import preliminary; import preliminary;
import logger;
/////////////////////////////////////// ///////////////////////////////////////
// ----------* INTERFACE *--------- // // ----------* INTERFACE *--------- //
@ -12,7 +14,7 @@ namespace lt::test {
class TestCase class TestCase
{ {
public: public:
TestCase(std::string_view name); TestCase(std::string name);
// NOLINTNEXTLINE(misc-unconventional-assign-operator) // NOLINTNEXTLINE(misc-unconventional-assign-operator)
auto operator=(std::invocable auto test) const -> void; auto operator=(std::invocable auto test) const -> void;
@ -21,7 +23,7 @@ private:
void run_normal(std::invocable auto test) const; void run_normal(std::invocable auto test) const;
private: private:
std::string_view m_name; std::string m_name;
}; };
struct TestSuite struct TestSuite
@ -68,16 +70,26 @@ void TestCase::run_normal(std::invocable auto test) const
} }
Registry::increment_matched_case_count(); Registry::increment_matched_case_count();
std::println("[Running-----------] --> "); auto padding = std::string {};
std::println("{}", m_name); padding.resize(79 - m_name.size());
for (auto &ch : padding)
{
ch = ' ';
}
try try
{ {
test(); test();
} }
catch (const std::exception &exp) catch (const std::exception &exp)
{ {
std::println("{}", exp.what()); log::test(
std::println("[-----------FAIL !!]"); "\033[1;31m{}{} | {}\033[0m",
std::string_view { m_name },
std::string { padding },
std::string { exp.what() }
);
Registry::increment_failed_case_count(); Registry::increment_failed_case_count();
if (Registry::should_return_on_failure()) if (Registry::should_return_on_failure())
@ -89,7 +101,9 @@ void TestCase::run_normal(std::invocable auto test) const
} }
Registry::increment_passed_case_count(); 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) TestSuite::TestSuite(auto body)
@ -123,8 +137,13 @@ auto operator""_suite(const char *name, size_t size) -> TestSuite
module :private; module :private;
namespace lt::test { 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 } // namespace lt::test

View file

@ -1,7 +1,14 @@
import test; import test;
Suite expects = "expects"_suite = []() { Suite expects = "expects"_suite = []() {
Case { "" } = [] { // should be truncated...
Case { "berryyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy "
"long name" }
= [] {
};
Case { "this emptiness machine" } = [] {
expect_le(9, 6);
}; };
Case { "expect_unreachable" } = [] { Case { "expect_unreachable" } = [] {