Skip to content

Commit

Permalink
Removed global state for reporters
Browse files Browse the repository at this point in the history
  • Loading branch information
cschreib committed May 19, 2024
1 parent c93b04b commit 3b3325a
Show file tree
Hide file tree
Showing 11 changed files with 70 additions and 48 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.")
Expand Down Expand Up @@ -222,6 +223,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()

Expand Down
3 changes: 3 additions & 0 deletions include/snitch/snitch_config.hpp.config
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 3 additions & 25 deletions include/snitch/snitch_macros_reporter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<TYPE> 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<typename T> \
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<TYPE>(NAME)

// clang-format off
#if SNITCH_WITH_SHORTHAND_MACROS
Expand Down
49 changes: 42 additions & 7 deletions include/snitch/snitch_registry.hpp
Original file line number Diff line number Diff line change
@@ -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"
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -102,6 +105,13 @@ struct registered_reporter {
finish_report_function finish = [](registry&) noexcept {};
};

template<typename T>
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<bool>;
} && requires(T& rep, const registry& reg, const event::data& e) { rep.report(reg, e); };

class registry {
// Contains all registered test cases.
small_vector<impl::test_case, max_test_cases> test_list;
Expand All @@ -112,8 +122,27 @@ class registry {
// Used when writing output to file.
std::optional<impl::file_writer> file_writer;

// the default console reporter
snitch::reporter::console::reporter console_reporter;
// Type-erased storage for the current reporter instance.
inplace_any<max_reporter_size_bytes> reporter_storage;

template<typename T>
void initialize_reporter(registry&) noexcept {
this->reporter_storage.emplace<T>(*this);
}

template<typename T>
void report(const registry&, const event::data& e) noexcept {
this->reporter_storage.get<T>().report(*this, e);
}

template<typename T>
bool configure_reporter(registry&, std::string_view k, std::string_view v) noexcept {
return this->reporter_storage.get<T>().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;
Expand All @@ -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<&registry::report_default>{}};
finish_report_function finish_callback = [](registry&) noexcept {};

// Internal API; do not use.
Expand Down Expand Up @@ -178,8 +206,15 @@ class registry {
const report_function& report,
const std::optional<finish_report_function>& finish);

// Internal API; do not use.
SNITCH_EXPORT std::string_view add_console_reporter();
// Requires: number of reporters + 1 <= max_registered_reporters.
template<reporter_type T>
std::string_view add_reporter(std::string_view name) {
return this->add_reporter(
name, initialize_report_function{*this, constant<&registry::initialize_reporter<T>>{}},
configure_report_function{*this, constant<&registry::configure_reporter<T>>{}},
report_function{*this, constant<&registry::report<T>>{}},
finish_report_function{*this, constant<&registry::destroy_reporter>{}});
}

// Internal API; do not use.
// Requires: number of tests + 1 <= max_test_cases, well-formed test ID.
Expand Down
2 changes: 1 addition & 1 deletion include/snitch/snitch_reporter_console.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.')
Expand Down
1 change: 1 addition & 0 deletions snitch/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
22 changes: 12 additions & 10 deletions src/snitch_registry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<default_reporter>()) {
reporter_storage.emplace<default_reporter>(*this);
}

reporter_storage.get<default_reporter>().report(*this, e);
}

const char*
Expand Down Expand Up @@ -1028,6 +1033,3 @@ small_vector_span<const registered_reporter> registry::reporters() const noexcep

constinit registry tests;
} // namespace snitch

static const std::string_view console_reporter_id [[maybe_unused]] =
snitch::tests.add_console_reporter();
6 changes: 3 additions & 3 deletions src/snitch_reporter_console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down Expand Up @@ -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);
2 changes: 1 addition & 1 deletion tests/approval_tests/reporter_console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<snitch::reporter::console::reporter>("console");

framework.registry.with_color = false;

Expand Down
2 changes: 1 addition & 1 deletion tests/testing_event.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ std::optional<snitch::source_location> get_location(const owning_event::data& e)
}

mock_framework::mock_framework() noexcept {
registry.add_console_reporter();
registry.add_reporter<snitch::reporter::console::reporter>("console");

registry.print_callback = [](std::string_view msg) noexcept {
snitch::cli::console_print(msg);
Expand Down

0 comments on commit 3b3325a

Please sign in to comment.