/** * * \section COPYRIGHT * * Copyright 2013-2020 Software Radio Systems Limited * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the distribution. * */ #include "src/srslog/log_backend_impl.h" #include "test_dummies.h" #include "testing_helpers.h" using namespace srslog; static bool when_backend_is_started_then_is_started_returns_true() { log_backend_impl backend; ASSERT_EQ(backend.is_running(), false); backend.start(); ASSERT_EQ(backend.is_running(), true); return true; } static bool when_backend_is_started_and_stopped_then_is_started_returns_false() { log_backend_impl backend; backend.start(); backend.stop(); ASSERT_EQ(backend.is_running(), false); return true; } namespace { /// A Spy implementation of a log sink. Tests can query the last received memory /// buffer by the sink and the number of invocations to the write method. class sink_spy : public sink { public: sink_spy() : sink(std::unique_ptr(new test_dummies::log_formatter_dummy)) {} detail::error_string write(detail::memory_buffer buffer) override { ++count; str.insert(0, buffer.data(), buffer.size()); return {}; } detail::error_string flush() override { return {}; } unsigned write_invocation_count() const { return count; } const std::string& received_buffer() const { return str; } private: unsigned count = 0; std::string str; }; } // namespace /// Builds a basic log entry. static detail::log_entry build_log_entry(sink* s) { using tp_ty = std::chrono::time_point; tp_ty tp; fmt::dynamic_format_arg_store store; store.push_back(88); return { s, [](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) {}, {tp, {0, false}, "Text %d", std::move(store), "", '\0', small_str_buffer()}}; } static bool when_backend_is_not_started_then_pushed_log_entries_are_ignored() { sink_spy spy; log_backend_impl backend; backend.push(build_log_entry(&spy)); ASSERT_EQ(spy.write_invocation_count(), 0); return true; } static bool when_backend_is_started_then_pushed_log_entries_are_sent_to_sink() { sink_spy spy; log_backend_impl backend; backend.start(); backend.push(build_log_entry(&spy)); // Stop the backend to ensure the entry has been processed. backend.stop(); ASSERT_EQ(spy.write_invocation_count(), 1); return true; } static bool when_backend_is_started_then_backend_invokes_format_func() { test_dummies::sink_dummy s; log_backend_impl backend; backend.start(); auto entry = build_log_entry(&s); unsigned counter = 0; entry.format_func = [&counter](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) { ++counter; }; backend.push(std::move(entry)); // Stop the backend to ensure the entry has been processed. backend.stop(); ASSERT_EQ(counter, 1); return true; } namespace { /// A Configurable Stub implementation of an object to be invoked by the /// backend. Upon invocation, instances of this class return an error that can /// be configured dynamically. class sink_error_stub : public sink { public: explicit sink_error_stub(std::string err) : sink(std::unique_ptr(new test_dummies::log_formatter_dummy)), err(std::move(err)) {} detail::error_string write(detail::memory_buffer buffer) override { return err; } detail::error_string flush() override { return err; } private: std::string err; }; } // namespace static bool when_sink_write_fails_then_error_handler_is_invoked() { std::string error_str("error"); sink_error_stub s(error_str); bool valid_err = false; unsigned count = 0; // valid_err checks that the input error matches the expected string. // The count variable counts the number of calls. auto handler = [&count, &valid_err, error_str](const std::string& error) { valid_err = (error == error_str); ++count; }; log_backend_impl backend; backend.set_error_handler(handler); backend.start(); backend.push(build_log_entry(&s)); // Stop the backend to ensure the entry has been processed. backend.stop(); ASSERT_EQ(valid_err, true); ASSERT_EQ(count, 1); return true; } static bool when_handler_is_set_after_start_then_handler_is_not_used() { sink_error_stub s("test"); unsigned count = 0; // The count variable counts the number of calls. auto handler = [&count](const std::string& error) { ++count; }; log_backend_impl backend; // We want to remove output to stderr by the default handler. backend.set_error_handler([](const std::string&) {}); backend.start(); backend.set_error_handler(handler); backend.push(build_log_entry(&s)); // Stop the backend to ensure the entry has been processed. backend.stop(); ASSERT_EQ(count, 0); return true; } static bool when_empty_handler_is_used_then_backend_does_not_crash() { sink_error_stub s("test"); log_backend_impl backend; // We want to remove output to stderr by the default handler. backend.set_error_handler({}); backend.start(); backend.push(build_log_entry(&s)); // Stop the backend to ensure the entry has been processed. backend.stop(); return true; } int main() { TEST_FUNCTION(when_backend_is_started_then_is_started_returns_true); TEST_FUNCTION( when_backend_is_started_and_stopped_then_is_started_returns_false); TEST_FUNCTION( when_backend_is_not_started_then_pushed_log_entries_are_ignored); TEST_FUNCTION( when_backend_is_started_then_pushed_log_entries_are_sent_to_sink); TEST_FUNCTION(when_backend_is_started_then_backend_invokes_format_func); TEST_FUNCTION(when_sink_write_fails_then_error_handler_is_invoked); TEST_FUNCTION(when_handler_is_set_after_start_then_handler_is_not_used); TEST_FUNCTION(when_empty_handler_is_used_then_backend_does_not_crash); return 0; }