From aab07c0720370ff58c8a1bfed66019d719c6f27e Mon Sep 17 00:00:00 2001 From: Ryan Date: Tue, 3 Sep 2024 01:43:56 +0200 Subject: [PATCH] Implement basic test functionality Closes #3 Closes #4 --- arc/validate/asserts.hxx | 27 ++++++ arc/validate/asserts.txx | 46 ++++++++++ arc/validate/command-line.cxx | 112 ++++++++++++++++++++++++ arc/validate/command-line.hxx | 46 ++++++++++ arc/validate/except.cxx | 27 ++++++ arc/validate/except.hxx | 88 +++++++++++++++++++ arc/validate/main.cxx | 155 ++++++++++++++++++++++++++++++++++ arc/validate/main.hxx | 22 +++++ arc/validate/test.cxx | 97 +++++++++++++++++++++ arc/validate/test.hxx | 79 +++++++++++++++++ arc/validate/version.hxx.in | 4 +- 11 files changed, 701 insertions(+), 2 deletions(-) create mode 100644 arc/validate/asserts.hxx create mode 100644 arc/validate/asserts.txx create mode 100644 arc/validate/command-line.cxx create mode 100644 arc/validate/command-line.hxx create mode 100644 arc/validate/except.cxx create mode 100644 arc/validate/except.hxx create mode 100644 arc/validate/main.cxx create mode 100644 arc/validate/main.hxx create mode 100644 arc/validate/test.cxx create mode 100644 arc/validate/test.hxx diff --git a/arc/validate/asserts.hxx b/arc/validate/asserts.hxx new file mode 100644 index 0000000..12232ac --- /dev/null +++ b/arc/validate/asserts.hxx @@ -0,0 +1,27 @@ +#ifndef arc__validate__asserts_hxx_ +#define arc__validate__asserts_hxx_ + +#include + +#include +#include + +#define ARC_VALIDATE_ASSERT_TRUE(expr) \ + ::arc::validate::asserts::assert_true(expr) + +namespace arc::validate::asserts +{ + + template + void + assert_true(T const&, std::source_location = std::source_location::current()); + + template + void + assert_false(T const&, std::source_location = std::source_location::current()); + +} // namespace arc::validate::asserts + +#include + +#endif diff --git a/arc/validate/asserts.txx b/arc/validate/asserts.txx new file mode 100644 index 0000000..6300153 --- /dev/null +++ b/arc/validate/asserts.txx @@ -0,0 +1,46 @@ +namespace arc::validate::asserts +{ + + template + void + assert_true(T const& expr, std::source_location origin) + { + struct extras_t + { + std::source_location origin; + + void + print(std::ostream& o) const + { + o << " assertion failed: " << origin.file_name() << ':' << origin.line() << '\n'; + } + + }; + + if (expr != true) { + throw failure_t{origin, "assertion failed", extras_t{origin}}; + } + } + + template + void + assert_false(T const& expr, std::source_location origin) + { + struct extras_t + { + std::source_location origin; + + void + print(std::ostream& o) const + { + o << " assertion failed: " << origin.file_name() << ':' << origin.line() << '\n'; + } + + }; + + if (expr != false) { + throw failure_t{origin, "assertion failed", extras_t{origin}}; + } + } + +} // namespace arc::validate::asserts diff --git a/arc/validate/command-line.cxx b/arc/validate/command-line.cxx new file mode 100644 index 0000000..ef880c3 --- /dev/null +++ b/arc/validate/command-line.cxx @@ -0,0 +1,112 @@ +#include + +namespace arc::validate +{ + + command_line_t + parse_command_line(std::vector const& args) + { + command_line_t command_line; + + bool only_files{false}; + + for (auto it = args.begin(); it != args.end(); ++it) { + auto const& option = *it; + + // fixme: should empty options be an error? + // + if (option.size() < 1) { + continue; + } + + if (only_files || '-' != option[0] || 1 == option.size()) { + throw command_line_error_t{"invalid file argument '" + option + "'"}; + } + + if ("--" == option) { + only_files = true; + continue; + } + + if ("--version" == option) { + command_line.print_version = true; + continue; + } + + if ("--help" == option) { + command_line.print_usage = true; + continue; + } + + if ("--print-information" == option) { + command_line.print_information = true; + continue; + } + + if ("--print-warnings" == option) { + command_line.print_warnings = true; + continue; + } + + if ("--print-success" == option) { + command_line.print_success = true; + continue; + } + + if ("--print-failure" == option) { + command_line.print_failure = true; + continue; + } + + if ("--verbose" == option) { + command_line.print_information = true; + command_line.print_warnings = true; + command_line.print_success = true; + command_line.print_failure = true; + continue; + } + + if ("-i" == option || "--include" == option) { + ++it; + + if (it == args.end()) { + throw command_line_error_t{"missing argument to '--include'"}; + } + + if (!command_line.exclude.empty()) { + throw command_line_error_t{"cannot specify both `-i, --include` and `-e, --exclude`"}; + } + + command_line.include.emplace(*it); + continue; + } + + if ("-e" == option || "--exclude" == option) { + ++it; + + if (it == args.end()) { + throw command_line_error_t{"missing argument to '--exclude'"}; + } + + if (!command_line.include.empty()) { + throw command_line_error_t{"cannot specify both `-i, --include` and `-e, --exclude`"}; + } + + command_line.exclude.emplace(*it); + continue; + } + + if ("-l" == option || "--list" == option) { + command_line.list = true; + continue; + } + + throw command_line_error_t{"unrecognized option '" + option + "'"}; + } + + + return command_line; + + } + +} diff --git a/arc/validate/command-line.hxx b/arc/validate/command-line.hxx new file mode 100644 index 0000000..9d04e6c --- /dev/null +++ b/arc/validate/command-line.hxx @@ -0,0 +1,46 @@ +#ifndef arc__validate__command_line_hxx_ +#define arc__validate__command_line_hxx_ + +#include + +#include +#include +#include +#include + +namespace arc::validate +{ + + struct LIBARC_VALIDATE_SYMEXPORT command_line_t + { + bool print_version{}; + bool print_usage{}; + bool print_information{}; + bool print_warnings{}; + bool print_success{}; + bool print_failure{}; + + std::set include; + std::set exclude; + + bool list{}; + + }; + + LIBARC_VALIDATE_SYMEXPORT + command_line_t + parse_command_line(std::vector const&); + + /// Exception class used to indicate command line error. + /// + class LIBARC_VALIDATE_SYMEXPORT command_line_error_t + : public std::runtime_error + { + public: + using std::runtime_error::runtime_error; + + }; + +} // namespace arc::validate + +#endif diff --git a/arc/validate/except.cxx b/arc/validate/except.cxx new file mode 100644 index 0000000..df40a4b --- /dev/null +++ b/arc/validate/except.cxx @@ -0,0 +1,27 @@ +#include + +namespace arc::validate +{ + + failure_t:: + failure_t(std::source_location origin, + std::string message, + extras_t extras) + : extras_{std::move(extras)} + {} + + failure_t::extras_t const& + failure_t:: + extras() const + { + return extras_; + } + + std::ostream& + operator<<(std::ostream& o, failure_t::extras_t const& extras) + { + extras.extras_->print(o); + return o; + } + +} // namespace arc::validate diff --git a/arc/validate/except.hxx b/arc/validate/except.hxx new file mode 100644 index 0000000..46ef155 --- /dev/null +++ b/arc/validate/except.hxx @@ -0,0 +1,88 @@ +#ifndef arc__validate__except_hxx_ +#define arc__validate__except_hxx_ + +#include + +#include +#include +#include +#include + +namespace arc::validate +{ + + class LIBARC_VALIDATE_SYMEXPORT skipped_t + {}; + + class LIBARC_VALIDATE_SYMEXPORT not_implemented_t + {}; + + class LIBARC_VALIDATE_SYMEXPORT failure_t + { + public: + class LIBARC_VALIDATE_SYMEXPORT extras_t + { + public: + template + extras_t(T extras) + : extras_{std::make_shared>(std::move(extras))} + {} + + friend + std::ostream& + operator<<(std::ostream&, extras_t const&); + + private: + struct concept_t + { + virtual + ~concept_t() noexcept = default; + + virtual + void + print(std::ostream&) const = 0; + + }; + + template + struct container_t + : concept_t + { + template + container_t(Args&&... args) + : extras{std::forward(args)...} + {} + + void + print(std::ostream& o) const + { + extras.print(o); + } + + T extras; + + }; + + std::shared_ptr extras_; + + }; + + failure_t(std::source_location, + std::string, + extras_t); + + extras_t const& + extras() const; + + private: + extras_t extras_; + + }; + + LIBARC_VALIDATE_SYMEXPORT + std::ostream& + operator<<(std::ostream&, failure_t::extras_t const&); + +} // namespace arc::validate + +#endif diff --git a/arc/validate/main.cxx b/arc/validate/main.cxx new file mode 100644 index 0000000..1736109 --- /dev/null +++ b/arc/validate/main.cxx @@ -0,0 +1,155 @@ +#include +#include +#include +#include +#include + +#include + +namespace arc::validate +{ + + static + void + print_version() + { + std::cout << "libarc-validate test runner (" << LIBARC_VALIDATE_VERSION_ID << ")\n"; + } + + static + void + print_usage(std::string const& execname) + { + std::cout << "Usage: " << execname << " [