From 72f1550ad7e12bb254c4d500c8430e1970395210 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Thu, 16 May 2024 21:01:47 +0100 Subject: [PATCH 1/3] Added type_id() --- CMakeLists.txt | 1 + include/snitch/snitch.hpp | 1 + include/snitch/snitch_type_id.hpp | 29 +++++++++++++++++++++++++++++ meson.build | 1 + tests/CMakeLists.txt | 1 + tests/runtime_tests/type_id.cpp | 30 ++++++++++++++++++++++++++++++ 6 files changed, 63 insertions(+) create mode 100644 include/snitch/snitch_type_id.hpp create mode 100644 tests/runtime_tests/type_id.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 95b8d9a5..4dfceef9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,6 +89,7 @@ set(SNITCH_INCLUDES ${PROJECT_SOURCE_DIR}/include/snitch/snitch_string.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_string_utility.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_test_data.hpp + ${PROJECT_SOURCE_DIR}/include/snitch/snitch_type_id.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_type_name.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_vector.hpp ${PROJECT_BINARY_DIR}/snitch/snitch_config.hpp) diff --git a/include/snitch/snitch.hpp b/include/snitch/snitch.hpp index 35a1008c..f38af2ba 100644 --- a/include/snitch/snitch.hpp +++ b/include/snitch/snitch.hpp @@ -31,6 +31,7 @@ #include "snitch/snitch_string.hpp" #include "snitch/snitch_string_utility.hpp" #include "snitch/snitch_test_data.hpp" +#include "snitch/snitch_type_id.hpp" #include "snitch/snitch_type_name.hpp" #include "snitch/snitch_vector.hpp" diff --git a/include/snitch/snitch_type_id.hpp b/include/snitch/snitch_type_id.hpp new file mode 100644 index 00000000..55e7a63e --- /dev/null +++ b/include/snitch/snitch_type_id.hpp @@ -0,0 +1,29 @@ +#ifndef SNITCH_TYPE_ID_HPP +#define SNITCH_TYPE_ID_HPP + +#include "snitch/snitch_config.hpp" + +namespace snitch { +using type_id_t = const void*; +} + +namespace snitch::impl { +template +struct type_id { + constexpr static char value = 0; +}; +} // namespace snitch::impl + +namespace snitch { +template +type_id_t type_id() noexcept { + return &impl::type_id::value; +} + +template<> +constexpr type_id_t type_id() noexcept { + return nullptr; +} +} // namespace snitch + +#endif diff --git a/meson.build b/meson.build index 41419361..072c3416 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,7 @@ headers = files('include/snitch/snitch.hpp', 'include/snitch/snitch_string_utility.hpp', 'include/snitch/snitch_test_data.hpp', 'include/snitch/snitch_type_name.hpp', + 'include/snitch/snitch_type_id.hpp', 'include/snitch/snitch_vector.hpp') sources = files('src/snitch_append.cpp', diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 47217c9d..0d6a7a6c 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -59,6 +59,7 @@ set(RUNTIME_TEST_FILES ${PROJECT_SOURCE_DIR}/tests/runtime_tests/small_string.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests/small_vector.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests/string_utility.cpp + ${PROJECT_SOURCE_DIR}/tests/runtime_tests/type_id.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests/type_name.cpp) set(APPROVAL_TEST_FILES diff --git a/tests/runtime_tests/type_id.cpp b/tests/runtime_tests/type_id.cpp new file mode 100644 index 00000000..f03e4699 --- /dev/null +++ b/tests/runtime_tests/type_id.cpp @@ -0,0 +1,30 @@ +#include "testing.hpp" + +#include + +using namespace std::literals; + +TEST_CASE("type id", "[utility]") { + SECTION("all unique") { + std::array types = { + snitch::type_id(), + snitch::type_id(), + snitch::type_id(), + snitch::type_id(), + snitch::type_id(), + snitch::type_id>(), + snitch::type_id>()}; + + CHECK(std::unique(types.begin(), types.end()) == types.end()); + } + + SECTION("constant") { + CHECK(snitch::type_id() == snitch::type_id()); + CHECK(snitch::type_id() == snitch::type_id()); + CHECK(snitch::type_id() == snitch::type_id()); + } + + SECTION("void") { + CHECK(snitch::type_id() == nullptr); + } +} From f8a5ec1b76bf6442b0d0cc0209a27a1c02564a08 Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Thu, 16 May 2024 21:03:04 +0100 Subject: [PATCH 2/3] Added inplace_any --- CMakeLists.txt | 1 + include/snitch/snitch.hpp | 1 + include/snitch/snitch_any.hpp | 108 +++++++++++++++++++++++++ meson.build | 1 + tests/CMakeLists.txt | 1 + tests/runtime_tests/any.cpp | 143 ++++++++++++++++++++++++++++++++++ 6 files changed, 255 insertions(+) create mode 100644 include/snitch/snitch_any.hpp create mode 100644 tests/runtime_tests/any.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4dfceef9..b654c1e8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -60,6 +60,7 @@ configure_file("${PROJECT_SOURCE_DIR}/include/snitch/snitch_config.hpp.config" set(SNITCH_INCLUDES ${PROJECT_SOURCE_DIR}/include/snitch/snitch.hpp + ${PROJECT_SOURCE_DIR}/include/snitch/snitch_any.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_append.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_capture.hpp ${PROJECT_SOURCE_DIR}/include/snitch/snitch_cli.hpp diff --git a/include/snitch/snitch.hpp b/include/snitch/snitch.hpp index f38af2ba..3fdbf709 100644 --- a/include/snitch/snitch.hpp +++ b/include/snitch/snitch.hpp @@ -1,6 +1,7 @@ #ifndef SNITCH_HPP #define SNITCH_HPP +#include "snitch/snitch_any.hpp" #include "snitch/snitch_append.hpp" #include "snitch/snitch_capture.hpp" #include "snitch/snitch_cli.hpp" diff --git a/include/snitch/snitch_any.hpp b/include/snitch/snitch_any.hpp new file mode 100644 index 00000000..238f7a7d --- /dev/null +++ b/include/snitch/snitch_any.hpp @@ -0,0 +1,108 @@ +#ifndef SNITCH_ANY_HPP +#define SNITCH_ANY_HPP + +#include "snitch/snitch_config.hpp" +#include "snitch/snitch_error_handling.hpp" +#include "snitch/snitch_function.hpp" +#include "snitch/snitch_type_id.hpp" + +#include +#include +#include + +namespace snitch { +namespace impl { +template +void delete_object(char* storage) noexcept { + reinterpret_cast(storage)->~T(); +} +} // namespace impl + +template +class inplace_any { + std::array storage = {}; + function_ref deleter = [](char*) noexcept {}; + type_id_t id = type_id(); + + void release() noexcept { + deleter = [](char*) noexcept {}; + id = type_id(); + } + +public: + constexpr inplace_any() = default; + + inplace_any(const inplace_any&) = delete; + + constexpr inplace_any(inplace_any&& other) noexcept : + storage(other.storage), deleter(other.deleter), id(other.id) { + other.release(); + } + + inplace_any& operator=(const inplace_any&) = delete; + + constexpr inplace_any& operator=(inplace_any&& other) noexcept { + reset(); + storage = other.storage; + deleter = other.deleter; + id = other.id; + other.release(); + return *this; + } + + template + explicit inplace_any(std::in_place_type_t, Args&&... args) { + emplace(std::forward(args)...); + } + + ~inplace_any() { + reset(); + } + + bool has_value() const noexcept { + return id != type_id(); + } + + type_id_t type() const noexcept { + return id; + } + + template + void emplace(Args&&... args) { + static_assert( + sizeof(T) <= MaxSize, + "This type is too large to fit in this inplace_any, increase storage size"); + + reset(); + new (storage.data()) T(std::forward(args)...); + deleter = &impl::delete_object; + id = type_id(); + } + + // Requires: not empty and stored type == T. + template + const T& get() const { + if (!has_value()) { + assertion_failed("inplace_any is empty"); + } + if (type() != type_id()) { + assertion_failed("inplace_any holds an object of a different type"); + } + + return *reinterpret_cast(storage.data()); + } + + // Requires: not empty and stored type == T. + template + T& get() { + return const_cast(const_cast(this)->get()); + } + + void reset() noexcept { + deleter(storage.data()); + release(); + } +}; +} // namespace snitch + +#endif diff --git a/meson.build b/meson.build index 072c3416..cdd9d637 100644 --- a/meson.build +++ b/meson.build @@ -28,6 +28,7 @@ add_project_link_arguments(cpp_arguments, language : 'cpp') include_dirs = include_directories('.', 'include') headers = files('include/snitch/snitch.hpp', + 'include/snitch/snitch_any.hpp', 'include/snitch/snitch_append.hpp', 'include/snitch/snitch_capture.hpp', 'include/snitch/snitch_cli.hpp', diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0d6a7a6c..e305022b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -46,6 +46,7 @@ set(TEST_UTILITY_FILES set(RUNTIME_TEST_FILES ${TEST_UTILITY_FILES} + ${PROJECT_SOURCE_DIR}/tests/runtime_tests/any.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests/capture.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests/check.cpp ${PROJECT_SOURCE_DIR}/tests/runtime_tests/cli.cpp diff --git a/tests/runtime_tests/any.cpp b/tests/runtime_tests/any.cpp new file mode 100644 index 00000000..f3f5b05f --- /dev/null +++ b/tests/runtime_tests/any.cpp @@ -0,0 +1,143 @@ +#include "testing.hpp" +#include "testing_assertions.hpp" + +namespace { +struct state_monitor { + int* state = nullptr; + + state_monitor() = default; + + explicit state_monitor(int* s) : state(s) { + *state += 1; + } + + ~state_monitor() { + *state -= 1; + } +}; +} // namespace + +TEST_CASE("any", "[utility]") { + constexpr std::size_t max_size = 16; + + int state1 = 0; + int state2 = 0; + + SECTION("default construct") { + snitch::inplace_any storage; + } + + SECTION("construct in-place") { + { + snitch::inplace_any storage(std::in_place_type_t{}, &state1); + CHECK(storage.has_value()); + CHECK(storage.type() == snitch::type_id()); + CHECK(state1 == 1); + CHECK(storage.get().state == &state1); + } + CHECK(state1 == 0); + } + + SECTION("move constructor") { + { + snitch::inplace_any storage1(std::in_place_type_t{}, &state1); + snitch::inplace_any storage2(std::move(storage1)); + CHECK(!storage1.has_value()); + CHECK(storage2.has_value()); + CHECK(state1 == 1); + } + CHECK(state1 == 0); + } + + SECTION("move assignment on empty") { + { + snitch::inplace_any storage2; + { + snitch::inplace_any storage1( + std::in_place_type_t{}, &state1); + storage2 = std::move(storage1); + CHECK(!storage1.has_value()); + } + + CHECK(storage2.has_value()); + CHECK(state1 == 1); + } + CHECK(state1 == 0); + } + + SECTION("move assignment on full") { + { + snitch::inplace_any storage2(std::in_place_type_t{}, &state2); + { + snitch::inplace_any storage1( + std::in_place_type_t{}, &state1); + storage2 = std::move(storage1); + CHECK(!storage1.has_value()); + } + + CHECK(storage2.has_value()); + CHECK(state1 == 1); + CHECK(state2 == 0); + } + CHECK(state1 == 0); + CHECK(state2 == 0); + } + + SECTION("emplace and reset") { + { + snitch::inplace_any storage; + storage.emplace(&state1); + CHECK(storage.has_value()); + CHECK(storage.type() == snitch::type_id()); + CHECK(state1 == 1); + CHECK(storage.get().state == &state1); + + storage.reset(); + CHECK(!storage.has_value()); + CHECK(state1 == 0); + } + CHECK(state1 == 0); + CHECK(state2 == 0); + } + + SECTION("emplace over existing") { + { + snitch::inplace_any storage; + storage.emplace(&state1); + storage.emplace(&state2); + CHECK(storage.has_value()); + CHECK(storage.type() == snitch::type_id()); + CHECK(state1 == 0); + CHECK(state2 == 1); + CHECK(storage.get().state == &state2); + } + CHECK(state1 == 0); + CHECK(state2 == 0); + } + + SECTION("reset empty") { + snitch::inplace_any storage; + storage.reset(); + CHECK(!storage.has_value()); + } + +#if SNITCH_WITH_EXCEPTIONS + SECTION("get empty") { + assertion_exception_enabler enabler; + snitch::inplace_any storage; + + CHECK_THROWS_WHAT( + storage.get(), assertion_exception, "inplace_any is empty"); + } + + SECTION("get wrong type") { + assertion_exception_enabler enabler; + snitch::inplace_any storage; + storage.emplace(0); + + CHECK_THROWS_WHAT( + storage.get(), assertion_exception, + "inplace_any holds an object of a different type"); + } +#endif +} From add06dc236deb0db8ec2f9512e4f303908ca51cf Mon Sep 17 00:00:00 2001 From: Corentin Schreiber Date: Thu, 16 May 2024 21:07:15 +0100 Subject: [PATCH 3/3] Removed global state for reporters --- CMakeLists.txt | 2 + include/snitch/snitch_config.hpp.config | 3 ++ include/snitch/snitch_macros_reporter.hpp | 28 ++----------- include/snitch/snitch_registry.hpp | 49 ++++++++++++++++++---- include/snitch/snitch_reporter_console.hpp | 2 +- meson_options.txt | 1 + snitch/meson.build | 1 + src/snitch_registry.cpp | 22 +++++----- src/snitch_reporter_console.cpp | 6 +-- tests/approval_tests/reporter_console.cpp | 2 +- tests/testing_event.cpp | 2 +- 11 files changed, 70 insertions(+), 48 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b654c1e8..5d791b06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ set(SNITCH_MAX_UNIQUE_TAGS 1024 CACHE STRING "Maximum number of unique set(SNITCH_MAX_COMMAND_LINE_ARGS 1024 CACHE STRING "Maximum number of command line arguments to a test application.") set(SNITCH_MAX_REGISTERED_REPORTERS 8 CACHE STRING "Maximum number of registered reporter that can be selected from the command line.") set(SNITCH_MAX_PATH_LENGTH 1024 CACHE STRING "Maximum length of a file path when writing output to file.") +set(SNITCH_MAX_REPORTER_SIZE_BYTES 128 CACHE STRING "Maximum size (in bytes) of a reporter object.") # Feature toggles. set(SNITCH_DEFINE_MAIN ON CACHE BOOL "Define main() in snitch -- disable to provide your own main() function.") @@ -221,6 +222,7 @@ if (SNITCH_DO_TEST) SNITCH_MAX_MESSAGE_LENGTH=129 SNITCH_MAX_TEST_NAME_LENGTH=130 SNITCH_MAX_CAPTURE_LENGTH=131 + SNITCH_MAX_REPORTER_SIZE_BYTES=16 SNITCH_DEFINE_MAIN=0) endfunction() diff --git a/include/snitch/snitch_config.hpp.config b/include/snitch/snitch_config.hpp.config index e8974880..fcce56c9 100644 --- a/include/snitch/snitch_config.hpp.config +++ b/include/snitch/snitch_config.hpp.config @@ -47,6 +47,9 @@ #if !defined(SNITCH_MAX_PATH_LENGTH) # define SNITCH_MAX_PATH_LENGTH ${SNITCH_MAX_PATH_LENGTH} #endif +#if !defined(SNITCH_MAX_REPORTER_SIZE_BYTES) +# define SNITCH_MAX_REPORTER_SIZE_BYTES ${SNITCH_MAX_REPORTER_SIZE_BYTES} +#endif #if !defined(SNITCH_DEFINE_MAIN) #cmakedefine01 SNITCH_DEFINE_MAIN #endif diff --git a/include/snitch/snitch_macros_reporter.hpp b/include/snitch/snitch_macros_reporter.hpp index ff18a119..91934758 100644 --- a/include/snitch/snitch_macros_reporter.hpp +++ b/include/snitch/snitch_macros_reporter.hpp @@ -9,31 +9,9 @@ static const std::string_view SNITCH_MACRO_CONCAT(reporter_id_, __COUNTER__) \ [[maybe_unused]] = snitch::tests.add_reporter(NAME, __VA_ARGS__) -#define SNITCH_REGISTER_REPORTER_IMPL(NAME, TYPE, COUNTER) \ - static std::optional SNITCH_MACRO_CONCAT(reporter_, COUNTER); \ - static void SNITCH_MACRO_CONCAT(reporter_init_, COUNTER)(snitch::registry & r) noexcept { \ - SNITCH_MACRO_CONCAT(reporter_, COUNTER).emplace(r); \ - } \ - template \ - static bool SNITCH_MACRO_CONCAT(reporter_config_, COUNTER)( \ - snitch::registry & r, std::string_view k, std::string_view v) noexcept { \ - return SNITCH_MACRO_CONCAT(reporter_, COUNTER)->configure(r, k, v); \ - } \ - static void SNITCH_MACRO_CONCAT(reporter_report_, COUNTER)( \ - const snitch::registry& r, const snitch::event::data& e) noexcept { \ - SNITCH_MACRO_CONCAT(reporter_, COUNTER)->report(r, e); \ - } \ - static void SNITCH_MACRO_CONCAT(reporter_finish_, COUNTER)(snitch::registry&) noexcept { \ - SNITCH_MACRO_CONCAT(reporter_, COUNTER).reset(); \ - } \ - static const std::string_view SNITCH_MACRO_CONCAT(reporter_id_, COUNTER) [[maybe_unused]] = \ - snitch::tests.add_reporter( \ - NAME, &SNITCH_MACRO_CONCAT(reporter_init_, COUNTER), \ - &SNITCH_MACRO_CONCAT(reporter_config_, COUNTER) < TYPE >, \ - &SNITCH_MACRO_CONCAT(reporter_report_, COUNTER), \ - &SNITCH_MACRO_CONCAT(reporter_finish_, COUNTER)) - -#define SNITCH_REGISTER_REPORTER(NAME, TYPE) SNITCH_REGISTER_REPORTER_IMPL(NAME, TYPE, __COUNTER__) +#define SNITCH_REGISTER_REPORTER(NAME, TYPE) \ + static const std::string_view SNITCH_MACRO_CONCAT(reporter_id_, __COUNTER__) \ + [[maybe_unused]] = snitch::tests.add_reporter(NAME) // clang-format off #if SNITCH_WITH_SHORTHAND_MACROS diff --git a/include/snitch/snitch_registry.hpp b/include/snitch/snitch_registry.hpp index 939f0918..6fe63d29 100644 --- a/include/snitch/snitch_registry.hpp +++ b/include/snitch/snitch_registry.hpp @@ -1,6 +1,7 @@ #ifndef SNITCH_REGISTRY_HPP #define SNITCH_REGISTRY_HPP +#include "snitch/snitch_any.hpp" #include "snitch/snitch_append.hpp" #include "snitch/snitch_cli.hpp" #include "snitch/snitch_config.hpp" @@ -34,6 +35,8 @@ constexpr std::size_t max_tag_length = SNITCH_MAX_TAG_LENGTH; constexpr std::size_t max_unique_tags = SNITCH_MAX_UNIQUE_TAGS; // Maximum number of registered reporters to select from the command line. constexpr std::size_t max_registered_reporters = SNITCH_MAX_REGISTERED_REPORTERS; +// Maximum size of a reporter instance, in bytes. +constexpr std::size_t max_reporter_size_bytes = SNITCH_MAX_REPORTER_SIZE_BYTES; } // namespace snitch namespace snitch::impl { @@ -102,6 +105,13 @@ struct registered_reporter { finish_report_function finish = [](registry&) noexcept {}; }; +template +concept reporter_type = + requires(registry& reg) { T{reg}; } && + requires(T& rep, registry& reg, std::string_view k, std::string_view v) { + { rep.configure(reg, k, v) } -> convertible_to; + } && requires(T& rep, const registry& reg, const event::data& e) { rep.report(reg, e); }; + class registry { // Contains all registered test cases. small_vector test_list; @@ -112,8 +122,27 @@ class registry { // Used when writing output to file. std::optional file_writer; - // the default console reporter - snitch::reporter::console::reporter console_reporter; + // Type-erased storage for the current reporter instance. + inplace_any reporter_storage; + + template + void initialize_reporter(registry&) noexcept { + this->reporter_storage.emplace(*this); + } + + template + void report(const registry&, const event::data& e) noexcept { + this->reporter_storage.get().report(*this, e); + } + + template + bool configure_reporter(registry&, std::string_view k, std::string_view v) noexcept { + return this->reporter_storage.get().configure(*this, k, v); + } + + SNITCH_EXPORT void destroy_reporter(registry&) noexcept; + + SNITCH_EXPORT void report_default(const registry&, const event::data& e) noexcept; public: enum class verbosity { quiet, normal, high, full } verbose = verbosity::normal; @@ -125,9 +154,8 @@ class registry { using report_function = snitch::report_function; using finish_report_function = snitch::finish_report_function; - print_function print_callback = &snitch::impl::stdout_print; - report_function report_callback = { - console_reporter, snitch::constant<&snitch::reporter::console::reporter::report>{}}; + print_function print_callback = &snitch::impl::stdout_print; + report_function report_callback = {*this, constant<®istry::report_default>{}}; finish_report_function finish_callback = [](registry&) noexcept {}; // Internal API; do not use. @@ -178,8 +206,15 @@ class registry { const report_function& report, const std::optional& finish); - // Internal API; do not use. - SNITCH_EXPORT std::string_view add_console_reporter(); + // Requires: number of reporters + 1 <= max_registered_reporters. + template + std::string_view add_reporter(std::string_view name) { + return this->add_reporter( + name, initialize_report_function{*this, constant<®istry::initialize_reporter>{}}, + configure_report_function{*this, constant<®istry::configure_reporter>{}}, + report_function{*this, constant<®istry::report>{}}, + finish_report_function{*this, constant<®istry::destroy_reporter>{}}); + } // Internal API; do not use. // Requires: number of tests + 1 <= max_test_cases, well-formed test ID. diff --git a/include/snitch/snitch_reporter_console.hpp b/include/snitch/snitch_reporter_console.hpp index f419a323..73743854 100644 --- a/include/snitch/snitch_reporter_console.hpp +++ b/include/snitch/snitch_reporter_console.hpp @@ -12,7 +12,7 @@ struct reporter { reporter() = default; - SNITCH_EXPORT void init(registry& r) noexcept; + SNITCH_EXPORT explicit reporter(registry& r) noexcept; SNITCH_EXPORT bool configure(registry&, std::string_view, std::string_view) noexcept; diff --git a/meson_options.txt b/meson_options.txt index 097599d2..18aad8d0 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -11,6 +11,7 @@ option('max_unique_tags' ,type: 'integer' ,value: 1024, description: 'M option('max_command_line_args' ,type: 'integer' ,value: 1024, description: 'Maximum number of command line arguments to a test application.') option('max_registered_reporters' ,type: 'integer' ,value: 8 , description: 'Maximum number of registered reporter that can be selected from the command line.') option('max_path_length' ,type: 'integer' ,value: 1024, description: 'Maximum length of a file path when writing output to file.') +option('max_reporter_size_bytes' ,type: 'integer' ,value: 128, description: 'Maximum size (in bytes) of a reporter object.') # Feature toggles. option('define_main' ,type: 'boolean' ,value: true, description: 'Define main() in snitch -- disable to provide your own main() function.') diff --git a/snitch/meson.build b/snitch/meson.build index b9f958cd..078b40bc 100644 --- a/snitch/meson.build +++ b/snitch/meson.build @@ -31,6 +31,7 @@ conf_data = configuration_data({ 'SNITCH_MAX_COMMAND_LINE_ARGS' : get_option('max_command_line_args'), 'SNITCH_MAX_REGISTERED_REPORTERS' : get_option('max_registered_reporters'), 'SNITCH_MAX_PATH_LENGTH' : get_option('max_path_length'), + 'SNITCH_MAX_REPORTER_SIZE_BYTES' : get_option('max_reporter_size_bytes'), 'SNITCH_DEFINE_MAIN' : get_option('define_main').to_int(), 'SNITCH_WITH_EXCEPTIONS' : get_option('with_exceptions').to_int(), diff --git a/src/snitch_registry.cpp b/src/snitch_registry.cpp index c5a08c20..796b97fc 100644 --- a/src/snitch_registry.cpp +++ b/src/snitch_registry.cpp @@ -336,13 +336,18 @@ std::string_view registry::add_reporter( return name; } -std::string_view registry::add_console_reporter() { - using reporter_type = snitch::reporter::console::reporter; - return add_reporter("console", - initialize_report_function{console_reporter, snitch::constant<&reporter_type::init>{}}, - configure_report_function{console_reporter, snitch::constant<&reporter_type::configure>{}}, - {console_reporter, snitch::constant<&snitch::reporter::console::reporter::report>{}}, - {}); +void registry::destroy_reporter(registry&) noexcept { + reporter_storage.reset(); +} + +void registry::report_default(const registry&, const event::data& e) noexcept { + using default_reporter = reporter::console::reporter; + + if (reporter_storage.type() != type_id()) { + reporter_storage.emplace(*this); + } + + reporter_storage.get().report(*this, e); } const char* @@ -1028,6 +1033,3 @@ small_vector_span registry::reporters() const noexcep constinit registry tests; } // namespace snitch - -static const std::string_view console_reporter_id [[maybe_unused]] = - snitch::tests.add_console_reporter(); diff --git a/src/snitch_reporter_console.cpp b/src/snitch_reporter_console.cpp index ff8ab098..b4ea916e 100644 --- a/src/snitch_reporter_console.cpp +++ b/src/snitch_reporter_console.cpp @@ -86,9 +86,7 @@ void print_message(const registry& r, const assertion_data& data) { } } // namespace -void reporter::init(registry&) noexcept { - counter = 0; -} +reporter::reporter(registry&) noexcept {} bool reporter::configure(registry& r, std::string_view option, std::string_view value) noexcept { if (option == "color") { @@ -205,3 +203,5 @@ void reporter::report(const registry& r, const event::data& event) noexcept { event); } } // namespace snitch::reporter::console + +SNITCH_REGISTER_REPORTER("console", snitch::reporter::console::reporter); diff --git a/tests/approval_tests/reporter_console.cpp b/tests/approval_tests/reporter_console.cpp index adf69338..86ec6ba4 100644 --- a/tests/approval_tests/reporter_console.cpp +++ b/tests/approval_tests/reporter_console.cpp @@ -13,7 +13,7 @@ TEST_CASE("console reporter", "[reporters]") { mock_framework framework; register_tests_for_reporters(framework.registry); - framework.registry.add_console_reporter(); + framework.registry.add_reporter("console"); framework.registry.with_color = false; diff --git a/tests/testing_event.cpp b/tests/testing_event.cpp index 5a8f48ca..9e8523e9 100644 --- a/tests/testing_event.cpp +++ b/tests/testing_event.cpp @@ -229,7 +229,7 @@ std::optional get_location(const owning_event::data& e) } mock_framework::mock_framework() noexcept { - registry.add_console_reporter(); + registry.add_reporter("console"); registry.print_callback = [](std::string_view msg) noexcept { snitch::cli::console_print(msg);