feat(test): add option parsing && the --stop-on-fail & -h options

This commit is contained in:
light7734 2025-09-29 09:47:59 +03:30
parent cce627a350
commit 723ade84ea
Signed by: light7734
GPG key ID: 8C30176798F1A6BA
2 changed files with 93 additions and 9 deletions

View file

@ -1,15 +1,59 @@
#include <test/test.hpp> #include <test/test.hpp>
auto main() -> int32_t using namespace ::lt::test;
using namespace ::lt::test::details;
void parse_option(std::string_view option, Registry::Options &options)
{
if (option == "--stop-on-fail")
{
options.stop_on_fail = true;
return;
}
throw std::invalid_argument { std::format("Invalid argument: {}", option) };
}
void print_help()
{
std::println("Options: ");
std::println("--stop-on-fail --> Stops executing the remaining tests on first failure");
std::println("--stats --> Print statistics about the tests without running any");
std::println("--help | -h --> ~You just used it! :D");
}
auto main(int32_t argc, char **argv) -> int32_t
try try
{ {
using namespace ::lt::test; auto raw_arguments = std::span<char *>(argv, argc);
using namespace ::lt::test::details;
return Registry::run_all(); auto options = Registry::Options {};
for (auto idx = 0; auto &raw_argument : raw_arguments)
{
// First argument is the "cwd'
if (idx++ == 0)
{
continue;
}
auto argument = std::string_view(raw_argument);
if (argument == "-h" || argument == "--help")
{
print_help();
return 0;
}
if (argument.starts_with("--") || argument.starts_with("-"))
{
parse_option(argument, options);
}
}
return Registry::run_all(options);
} }
catch (const std::exception &exp) catch (const std::exception &exp)
{ {
std::cout << "Terminated after uncaught exception:\n"; // NOLINT std::cout << "Terminated after uncaught exception:\n";
std::cout << "exception.what: " << exp.what(); std::cout << "exception.what: " << exp.what();
} }

View file

@ -10,6 +10,11 @@ namespace details {
class Registry class Registry
{ {
public: public:
struct Options
{
bool stop_on_fail = false;
};
using FuzzFunction = int32_t (*)(const uint8_t *, size_t); using FuzzFunction = int32_t (*)(const uint8_t *, size_t);
using SuiteFunction = void (*)(); using SuiteFunction = void (*)();
@ -30,11 +35,29 @@ public:
instance().m_fuzz_harness = suite; instance().m_fuzz_harness = suite;
} }
static auto run_all() -> int32_t static auto run_all(Options options) -> int32_t
{ {
instance().m_options = options;
instance().print_options();
for (auto &test : instance().m_suites) for (auto &test : instance().m_suites)
{ {
test(); try
{
test();
}
catch (const std::exception &exp)
{
if (options.stop_on_fail)
{
std::println("Quitting due to options.stop_on_fail == true");
break;
}
std::println("Uncaught exception when running suite:");
std::println("\twhat: {}", exp.what());
break;
}
} }
std::cout << "Ran " << instance().m_failed_count + instance().m_pasesed_count << " tests:\n" std::cout << "Ran " << instance().m_failed_count + instance().m_pasesed_count << " tests:\n"
@ -67,7 +90,17 @@ public:
++instance().m_failed_count; ++instance().m_failed_count;
} }
static auto should_return_on_failure() -> bool
{
return instance().m_options.stop_on_fail;
}
private: private:
void print_options()
{
std::println("stop-on-failure: {}", m_options.stop_on_fail);
}
Registry() Registry()
{ {
std::cout << "________________________________________________________________\n"; std::cout << "________________________________________________________________\n";
@ -79,6 +112,8 @@ private:
return registry; return registry;
} }
Options m_options {};
std::vector<SuiteFunction> m_suites; std::vector<SuiteFunction> m_suites;
FuzzFunction m_fuzz_harness {}; FuzzFunction m_fuzz_harness {};
@ -92,7 +127,8 @@ private:
struct Case struct Case
{ {
auto operator=(std::invocable auto test) -> void // NOLINT // NOLINTNEXTLINE(misc-unconventional-assign-operator)
auto operator=(std::invocable auto test) -> void
{ {
std::cout << "[Running-----------] --> "; std::cout << "[Running-----------] --> ";
std::cout << name << '\n'; std::cout << name << '\n';
@ -106,7 +142,11 @@ struct Case
std::cout << exp.what() << "\n"; std::cout << exp.what() << "\n";
std::cout << "[-----------FAIL !!]" << "\n\n"; std::cout << "[-----------FAIL !!]" << "\n\n";
details::Registry::increment_failed_count(); details::Registry::increment_failed_count();
return; // TODO(Light): Should we run the remaining tests after a failure?
if (details::Registry::should_return_on_failure())
{
throw;
}
} }
details::Registry::increment_passed_count(); details::Registry::increment_passed_count();