bleh
This commit is contained in:
parent
6e5045f1f4
commit
693fa17d10
266 changed files with 60543 additions and 1000 deletions
2
subprojects/quill-4.2.0/quill/test/CMakeLists.txt
Normal file
2
subprojects/quill-4.2.0/quill/test/CMakeLists.txt
Normal file
|
@ -0,0 +1,2 @@
|
|||
add_subdirectory(unit_tests)
|
||||
add_subdirectory(integration_tests)
|
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016-2019 Viktor Kirilov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
7106
subprojects/quill-4.2.0/quill/test/bundled/doctest/doctest.h
Normal file
7106
subprojects/quill-4.2.0/quill/test/bundled/doctest/doctest.h
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,143 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("arithmetic_types_logging")
|
||||
{
|
||||
static constexpr char const* filename = "arithmetic_types_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
BackendOptions bo;
|
||||
bo.error_notifier = [](std::string const&) {};
|
||||
Backend::start(bo);
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
bool b = true;
|
||||
LOG_INFO(logger, "v [{}]", b);
|
||||
|
||||
char c = 'a';
|
||||
LOG_INFO(logger, "c [{}]", c);
|
||||
|
||||
short int si = -12;
|
||||
LOG_INFO(logger, "si [{}]", si);
|
||||
|
||||
int i = -123;
|
||||
LOG_INFO(logger, "i [{}]", i);
|
||||
|
||||
long int li = 9876;
|
||||
LOG_INFO(logger, "li [{}]", li);
|
||||
|
||||
long long int lli = 321;
|
||||
LOG_INFO(logger, "lli [{}]", lli);
|
||||
|
||||
unsigned short int usi = 15;
|
||||
LOG_INFO(logger, "usi [{}]", usi);
|
||||
|
||||
unsigned int ui = 123;
|
||||
LOG_INFO(logger, "ui [{}]", ui);
|
||||
|
||||
unsigned long int uli = 2876;
|
||||
LOG_INFO(logger, "uli [{}]", uli);
|
||||
|
||||
unsigned long long int ulli = 1321;
|
||||
LOG_INFO(logger, "ulli [{}]", ulli);
|
||||
|
||||
float f = 323.31f;
|
||||
LOG_INFO(logger, "f [{}]", f);
|
||||
|
||||
double d = 3213213.123;
|
||||
LOG_INFO(logger, "d [{}]", d);
|
||||
|
||||
int const& cri = i;
|
||||
LOG_INFO(logger, "cri [{}]", cri);
|
||||
|
||||
int& ci = i;
|
||||
LOG_INFO(logger, "ci [{}]", ci);
|
||||
|
||||
LOG_INFO(logger, "invalid format [{%f}]", 321.1);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
REQUIRE_FALSE(Backend::is_running());
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " v [true]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c [a]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli [2876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [1321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f [323.31]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [3213213.123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" [Could not format log statement. message: \"invalid format [{%f}]\""}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
#if !defined(QUILL_NO_EXCEPTIONS)
|
||||
|
||||
/***/
|
||||
TEST_CASE("backend_exception_notifier")
|
||||
{
|
||||
static constexpr char const* filename = "backend_exception_notifier.log";
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger("logger", std::move(file_sink));
|
||||
|
||||
// counter to check our error handler was invoked
|
||||
// atomic because we check this value on this thread, but the backend worker thread updates it
|
||||
std::atomic<size_t> error_notifier_invoked{0};
|
||||
|
||||
// Set invalid thread name
|
||||
BackendOptions backend_options;
|
||||
|
||||
// Setting to an invalid CPU. When we call quill::start() our error handler will be invoked and an error will be logged
|
||||
backend_options.backend_cpu_affinity = static_cast<uint16_t>(std::numeric_limits<uint16_t>::max() - 1);
|
||||
|
||||
backend_options.thread_name =
|
||||
"Lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt_ut_"
|
||||
"labore_et_dolore_magna_aliqua";
|
||||
|
||||
backend_options.error_notifier = [logger, &error_notifier_invoked](std::string const& error_message)
|
||||
{
|
||||
// Log inside the function from the backend thread, for testing
|
||||
|
||||
// Note that this log is asynchronous here which means when error_notifier_invoked is
|
||||
// incremented does not mean we have logged this yet
|
||||
|
||||
// flush_log() is not permitted inside this callback
|
||||
LOG_WARNING(logger, "error handler invoked {}", error_message);
|
||||
|
||||
error_notifier_invoked.fetch_add(1);
|
||||
};
|
||||
|
||||
Backend::start(backend_options);
|
||||
|
||||
// Log a message and wait for it to get processed, that way we know the backend thread has started
|
||||
LOG_INFO(logger, "frontend");
|
||||
logger->flush_log();
|
||||
|
||||
// Check our handler was invoked since either set_backend_thread_name or set_backend_thread_cpu_affinity should have failed
|
||||
REQUIRE_GE(error_notifier_invoked.load(), 1);
|
||||
|
||||
// Now we can try to get another exception by calling LOG_BACKTRACE without calling init first
|
||||
error_notifier_invoked.store(0);
|
||||
|
||||
LOG_BACKTRACE(logger, "Backtrace message");
|
||||
logger->flush_log();
|
||||
|
||||
// Check our handler was invoked
|
||||
REQUIRE_EQ(error_notifier_invoked.load(), 1);
|
||||
|
||||
// Pass an invalid fmt format and see if it throws
|
||||
error_notifier_invoked.store(0);
|
||||
|
||||
LOG_INFO(logger, "Format {:>321.}", 321.3);
|
||||
logger->flush_log();
|
||||
|
||||
// Check our handler was invoked
|
||||
REQUIRE_EQ(error_notifier_invoked.load(), 1);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// After the backend has stopped, all messages include the async ones from the notifier will
|
||||
// be in the log file. At this point we can safely check it
|
||||
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_GE(file_contents.size(), 5);
|
||||
|
||||
// Look for the async errors
|
||||
std::string const expected_string_1 = "error handler invoked Failed to set cpu affinity ";
|
||||
std::string const expected_string_2 = "error handler invoked Failed to set thread name ";
|
||||
|
||||
bool const has_any_error = quill::testing::file_contains(file_contents, expected_string_1) ||
|
||||
quill::testing::file_contains(file_contents, expected_string_2);
|
||||
|
||||
REQUIRE(has_any_error);
|
||||
|
||||
std::string const expected_string_3 = "error handler invoked logger->init_backtrace(...)";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
|
||||
|
||||
std::string const expected_string_4 = "error handler invoked [Could not format log statement.";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,90 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backend_long_sleep_and_notify")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 100u;
|
||||
static constexpr size_t number_of_threads = 4;
|
||||
static constexpr char const* filename = "log_backend_long_sleep_and_notify.log";
|
||||
static std::string const logger_name_prefix = "logger_";
|
||||
|
||||
// Start the backend thread
|
||||
BackendOptions backend_options;
|
||||
backend_options.sleep_duration = std::chrono::hours{24};
|
||||
Backend::start(backend_options);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
threads.emplace_back(
|
||||
[i]() mutable
|
||||
{
|
||||
// Also use preallocate
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger =
|
||||
Frontend::create_or_get_logger(logger_name_prefix + std::to_string(i), std::move(file_sink));
|
||||
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
LOG_INFO(logger, "Hello from thread {thread_index} this is message {message_num}", i, j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& elem : threads)
|
||||
{
|
||||
elem.join();
|
||||
}
|
||||
|
||||
// The backend worker is still sleeping here so no file should exist
|
||||
REQUIRE_EQ(testing::file_contents(filename).size(), 0);
|
||||
|
||||
// Notify the backend to wake up and process
|
||||
Backend::notify();
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads);
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
// for each thread
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
std::string expected_string = logger_name_prefix + std::to_string(i) +
|
||||
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j);
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backend_transit_buffer_hard_limit")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 500u;
|
||||
static constexpr size_t number_of_threads = 10;
|
||||
static constexpr char const* filename = "backend_transit_buffer_hard_limit.log";
|
||||
static std::string const logger_name_prefix = "logger_";
|
||||
|
||||
// Start the backend thread
|
||||
BackendOptions backend_options;
|
||||
backend_options.transit_events_hard_limit = 0;
|
||||
backend_options.transit_event_buffer_initial_capacity = 0;
|
||||
Backend::start(backend_options);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
threads.emplace_back(
|
||||
[i]() mutable
|
||||
{
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger =
|
||||
Frontend::create_or_get_logger(logger_name_prefix + std::to_string(i), std::move(file_sink));
|
||||
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
LOG_INFO(logger, "Hello from thread {thread_index} this is message {message_num}", i, j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& elem : threads)
|
||||
{
|
||||
elem.join();
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads);
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
// for each thread
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
std::string expected_string = logger_name_prefix + std::to_string(i) +
|
||||
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j);
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backend_transit_buffer_soft_limit")
|
||||
{
|
||||
static constexpr char const* filename = "backend_transit_buffer_soft_limit.log";
|
||||
static std::string const logger_name = "logger";
|
||||
size_t constexpr soft_limit = 100;
|
||||
|
||||
// First log some messages and then start the backend worker thread so that the soft limit is hit
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
for (size_t i = 0; i < soft_limit * 2; ++i)
|
||||
{
|
||||
// log all messages
|
||||
LOG_INFO(logger, "Message num {}", i);
|
||||
}
|
||||
|
||||
// Start the backend thread
|
||||
BackendOptions backend_options;
|
||||
backend_options.transit_events_soft_limit = soft_limit;
|
||||
Backend::start(backend_options);
|
||||
|
||||
// log more messages after the backend started
|
||||
for (size_t i = soft_limit * 2; i < soft_limit * 4; ++i)
|
||||
{
|
||||
// log all messages
|
||||
LOG_INFO(logger, "Message num {}", i);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = testing::file_contents(filename);
|
||||
|
||||
size_t const total_messages = soft_limit * 4;
|
||||
REQUIRE_EQ(file_contents.size(), total_messages);
|
||||
|
||||
for (size_t i = 0; i < total_messages; ++i)
|
||||
{
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Message num "} + std::to_string(i)));
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backtrace_dynamic_log_level")
|
||||
{
|
||||
static constexpr char const* filename = "backtrace_dynamic_log_level.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
// Enable backtrace for 2 messages for error
|
||||
logger->init_backtrace(2, LogLevel::Error);
|
||||
|
||||
// log using dynamic log level and flush on warning instead
|
||||
LOG_DYNAMIC(logger, LogLevel::Info, "Before dynamic backtrace log");
|
||||
for (size_t i = 100; i < 120; ++i)
|
||||
{
|
||||
#if defined(__aarch64__) || ((__ARM_ARCH >= 6) || defined(_M_ARM64))
|
||||
// On ARM we add a small delay because log messages can get the same timestamp from rdtsc
|
||||
// when in this loop and make the test unstable
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{200});
|
||||
#endif
|
||||
LOG_DYNAMIC(logger, LogLevel::Backtrace, "Dynamic backtrace log {}", i);
|
||||
}
|
||||
|
||||
LOG_DYNAMIC(logger, LogLevel::Error, "After dynamic error");
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), 4);
|
||||
|
||||
std::string expected_string_1 =
|
||||
"LOG_INFO " + logger_name + " Before dynamic backtrace log";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
|
||||
|
||||
std::string expected_string_2 = "LOG_ERROR " + logger_name + " After dynamic error";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
|
||||
|
||||
std::string expected_string_3 =
|
||||
"LOG_BACKTRACE " + logger_name + " Dynamic backtrace log 118";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
|
||||
|
||||
std::string expected_string_4 =
|
||||
"LOG_BACKTRACE " + logger_name + " Dynamic backtrace log 119";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backtrace_flush_on_error")
|
||||
{
|
||||
static constexpr char const* filename = "backtrace_flush_on_error.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
// Enable backtrace for 2 messages for error
|
||||
logger->init_backtrace(2, LogLevel::Error);
|
||||
|
||||
// flush backtrace on error
|
||||
LOG_INFO(logger, "Before backtrace log");
|
||||
for (size_t i = 0; i < 12; ++i)
|
||||
{
|
||||
#if defined(__aarch64__) || ((__ARM_ARCH >= 6) || defined(_M_ARM64))
|
||||
// On ARM we add a small delay because log messages can get the same timestamp from rdtsc
|
||||
// when in this loop and make the test unstable
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{200});
|
||||
#endif
|
||||
LOG_BACKTRACE(logger, "Backtrace log {}", i);
|
||||
}
|
||||
LOG_ERROR(logger, "After error");
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), 4);
|
||||
|
||||
std::string expected_string_1 = "LOG_INFO " + logger_name + " Before backtrace log";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
|
||||
|
||||
std::string expected_string_2 = "LOG_ERROR " + logger_name + " After error";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
|
||||
|
||||
std::string expected_string_3 = "LOG_BACKTRACE " + logger_name + " Backtrace log 10";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
|
||||
|
||||
std::string expected_string_4 = "LOG_BACKTRACE " + logger_name + " Backtrace log 11";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backtrace_manual_flush")
|
||||
{
|
||||
static constexpr char const* filename = "backtrace_manual_flush.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
// Enable backtrace for 2 messages for error
|
||||
logger->init_backtrace(2, LogLevel::Error);
|
||||
|
||||
// flush backtrace on error
|
||||
LOG_INFO(logger, "Before backtrace log");
|
||||
for (size_t i = 0; i < 12; ++i)
|
||||
{
|
||||
#if defined(__aarch64__) || ((__ARM_ARCH >= 6) || defined(_M_ARM64))
|
||||
// On ARM we add a small delay because log messages can get the same timestamp from rdtsc
|
||||
// when in this loop and make the test unstable
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{200});
|
||||
#endif
|
||||
LOG_BACKTRACE(logger, "Backtrace log {}", i);
|
||||
}
|
||||
|
||||
logger->flush_backtrace();
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), 3);
|
||||
|
||||
std::string expected_string_1 = "LOG_INFO " + logger_name + " Before backtrace log";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
|
||||
|
||||
std::string expected_string_3 = "LOG_BACKTRACE " + logger_name + " Backtrace log 10";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
|
||||
|
||||
std::string expected_string_4 = "LOG_BACKTRACE " + logger_name + " Backtrace log 11";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backtrace_no_flush")
|
||||
{
|
||||
static constexpr char const* filename = "backtrace_no_flush.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
// Enable backtrace for 2 messages for warning
|
||||
logger->init_backtrace(2, LogLevel::Error);
|
||||
|
||||
// try with LOG_WARNING and expect no flush
|
||||
LOG_INFO(logger, "Before backtrace log retry");
|
||||
for (size_t i = 0; i < 12; ++i)
|
||||
{
|
||||
LOG_BACKTRACE(logger, "Backtrace log {}", i);
|
||||
}
|
||||
LOG_WARNING(logger, "After backtrace log retry");
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), 2);
|
||||
|
||||
std::string expected_string_1 =
|
||||
"LOG_INFO " + logger_name + " Before backtrace log retry";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
|
||||
|
||||
std::string expected_string_2 =
|
||||
"LOG_WARNING " + logger_name + " After backtrace log retry";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("backtrace_terminated_thread_flush")
|
||||
{
|
||||
// In this test we store in backtrace from one thread that terminates
|
||||
// then we log that backtrace from a different thread
|
||||
|
||||
static constexpr char const* filename = "backtrace_terminated_thread_flush.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
std::thread thread_a(
|
||||
[]()
|
||||
{
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// Get a logger and enable backtrace
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
// Enable backtrace for 2 messages
|
||||
logger->init_backtrace(2, LogLevel::Error);
|
||||
|
||||
LOG_INFO(logger, "Before backtrace log");
|
||||
for (uint32_t i = 0; i < 12; ++i)
|
||||
{
|
||||
LOG_BACKTRACE(logger, "Backtrace message {}", i);
|
||||
}
|
||||
});
|
||||
|
||||
thread_a.join();
|
||||
|
||||
// thread_a logged something in backtrace and finished.
|
||||
// Now we spawn a different thread and LOG_ERROR
|
||||
// we expect to see the backtrace from the previous thread
|
||||
std::thread thread_b(
|
||||
[]()
|
||||
{
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// Get a logger and enable backtrace
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
LOG_ERROR(logger, "After error");
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
});
|
||||
|
||||
thread_b.join();
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), 4);
|
||||
|
||||
std::string expected_string_1 = "LOG_INFO " + logger_name + " Before backtrace log";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_1));
|
||||
|
||||
std::string expected_string_2 = "LOG_ERROR " + logger_name + " After error";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_2));
|
||||
|
||||
std::string expected_string_3 = "LOG_BACKTRACE " + logger_name + " Backtrace message 10";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_3));
|
||||
|
||||
std::string expected_string_4 = "LOG_BACKTRACE " + logger_name + " Backtrace message 11";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string_4));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
// Define custom Frontend Options
|
||||
struct CustomFrontendOptions
|
||||
{
|
||||
static constexpr quill::QueueType queue_type = quill::QueueType::BoundedBlocking;
|
||||
static constexpr uint32_t initial_queue_capacity = 131'072;
|
||||
static constexpr uint32_t blocking_queue_retry_interval_ns = 800;
|
||||
static constexpr bool huge_pages_enabled = false;
|
||||
};
|
||||
|
||||
using CustomFrontend = FrontendImpl<CustomFrontendOptions>;
|
||||
using CustomLogger = LoggerImpl<CustomFrontendOptions>;
|
||||
|
||||
TEST_CASE("bounded_blocking_queue")
|
||||
{
|
||||
static constexpr char const* filename = "bounded_blocking_queue.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
auto file_sink = CustomFrontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
CustomLogger* logger = CustomFrontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
for (int i = 0; i < 5000; ++i)
|
||||
{
|
||||
LOG_INFO(logger, "Log something to fulfill the bound queue {}", i);
|
||||
LOG_WARNING(logger, "Log something to fulfill the bound queue {}", i);
|
||||
LOG_ERROR(logger, "Log something to fulfill the bound queue {}", i);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check the first messages as we can't if some were dropped
|
||||
std::vector<std::string> const file_contents = testing::file_contents(filename);
|
||||
|
||||
for (int i = 0; i < 5000; ++i)
|
||||
{
|
||||
std::string expected_string_1 = "LOG_INFO " + logger_name +
|
||||
" Log something to fulfill the bound queue " + std::to_string(i);
|
||||
|
||||
std::string expected_string_2 = "LOG_WARNING " + logger_name +
|
||||
" Log something to fulfill the bound queue " + std::to_string(i);
|
||||
|
||||
std::string expected_string_3 = "LOG_ERROR " + logger_name +
|
||||
" Log something to fulfill the bound queue " + std::to_string(i);
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string_1));
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string_2));
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string_3));
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
// Define custom Frontend Options
|
||||
struct CustomFrontendOptions
|
||||
{
|
||||
static constexpr quill::QueueType queue_type = quill::QueueType::BoundedDropping;
|
||||
static constexpr uint32_t initial_queue_capacity = 131'072;
|
||||
static constexpr uint32_t blocking_queue_retry_interval_ns = 800;
|
||||
static constexpr bool huge_pages_enabled = false;
|
||||
};
|
||||
|
||||
using CustomFrontend = FrontendImpl<CustomFrontendOptions>;
|
||||
using CustomLogger = LoggerImpl<CustomFrontendOptions>;
|
||||
|
||||
TEST_CASE("bounded_dropping_queue")
|
||||
{
|
||||
static constexpr char const* filename = "bounded_dropping_queue.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
auto file_sink = CustomFrontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
CustomLogger* logger = CustomFrontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
for (int i = 0; i < 5000; ++i)
|
||||
{
|
||||
LOG_INFO(logger, "Log something to fulfill the bound queue {}", i);
|
||||
LOG_WARNING(logger, "Log something to fulfill the bound queue {}", i);
|
||||
LOG_ERROR(logger, "Log something to fulfill the bound queue {}", i);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check the first messages as we can't if some were dropped
|
||||
std::vector<std::string> const file_contents = testing::file_contents(filename);
|
||||
|
||||
for (int i = 0; i < 100; ++i)
|
||||
{
|
||||
std::string expected_string_1 = "LOG_INFO " + logger_name +
|
||||
" Log something to fulfill the bound queue " + std::to_string(i);
|
||||
|
||||
std::string expected_string_2 = "LOG_WARNING " + logger_name +
|
||||
" Log something to fulfill the bound queue " + std::to_string(i);
|
||||
|
||||
std::string expected_string_3 = "LOG_ERROR " + logger_name +
|
||||
" Log something to fulfill the bound queue " + std::to_string(i);
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string_1));
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string_2));
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string_3));
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
function(quill_add_test TEST_NAME SOURCES)
|
||||
set(HEADER_FILES
|
||||
${PROJECT_SOURCE_DIR}/quill/test/bundled/doctest/doctest.h
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/TestUtilities.h
|
||||
)
|
||||
|
||||
set(ADD_SOURCE_FILES
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/TestMain.cpp
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/TestUtilities.cpp
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/DocTestExtensions.cpp)
|
||||
|
||||
list(APPEND SOURCES ${ADD_SOURCE_FILES})
|
||||
|
||||
# Create a test executable
|
||||
add_executable(${TEST_NAME} "")
|
||||
|
||||
set_common_compile_options(${TEST_NAME})
|
||||
|
||||
# Add sources
|
||||
target_sources(${TEST_NAME} PRIVATE ${SOURCES} ${HEADER_FILES})
|
||||
|
||||
# include dirs
|
||||
target_include_directories(${TEST_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/quill/test/misc>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/quill/test/bundled>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/quill/test)
|
||||
|
||||
# Link dependencies
|
||||
target_link_libraries(${TEST_NAME} quill)
|
||||
|
||||
# Do not decay cxx standard if not specified
|
||||
set_property(TARGET ${TEST_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Set output test directory
|
||||
set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/test)
|
||||
|
||||
# Add this target to the post build unit tests
|
||||
doctest_discover_tests(${TEST_NAME})
|
||||
endfunction()
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/doctest.cmake)
|
||||
|
||||
quill_add_test(TEST_ArithmeticTypesLogging ArithmeticTypesLoggingTest.cpp)
|
||||
quill_add_test(TEST_BackendExceptionNotifier BackendExceptionNotifierTest.cpp)
|
||||
quill_add_test(TEST_BackendLongSleepAndNotify BackendLongSleepAndNotifyTest.cpp)
|
||||
quill_add_test(TEST_BackendTransitBufferHardLimit BackendTransitBufferHardLimitTest.cpp)
|
||||
quill_add_test(TEST_BackendTransitBufferSoftLimit BackendTransitBufferSoftLimitTest.cpp)
|
||||
quill_add_test(TEST_BacktraceDynamicLogLevel BacktraceDynamicLogLevelTest.cpp)
|
||||
quill_add_test(TEST_BacktraceFlushOnError BacktraceFlushOnErrorTest.cpp)
|
||||
quill_add_test(TEST_BacktraceManualFlush BacktraceManualFlushTest.cpp)
|
||||
quill_add_test(TEST_BacktraceNoFlush BacktraceNoFlushTest.cpp)
|
||||
quill_add_test(TEST_BacktraceTerminatedThreadFlush BacktraceTerminatedThreadFlushTest.cpp)
|
||||
quill_add_test(TEST_BoundedBlockingQueue BoundedBlockingQueueTest.cpp)
|
||||
quill_add_test(TEST_BoundedDroppingQueue BoundedDroppingQueueTest.cpp)
|
||||
quill_add_test(TEST_ConsoleSinkStderrMultipleFormats ConsoleSinkStderrMultipleFormatsTest.cpp)
|
||||
quill_add_test(TEST_ConsoleSinkStdoutMultipleFormats ConsoleSinkStdoutMultipleFormatsTest.cpp)
|
||||
quill_add_test(TEST_LoggerAddRemoveGet LoggerAddRemoveGetTest.cpp)
|
||||
quill_add_test(TEST_EnumLogging EnumLoggingTest.cpp)
|
||||
quill_add_test(TEST_FlushWithoutAnyLog FlushWithoutAnyLog.cpp)
|
||||
quill_add_test(TEST_JsonConsoleLoggingTest JsonConsoleLoggingTest.cpp)
|
||||
quill_add_test(TEST_JsonFileLogging JsonFileLoggingTest.cpp)
|
||||
quill_add_test(TEST_LogArgumentsEvaluation LogArgumentsEvaluationTest.cpp)
|
||||
quill_add_test(TEST_LogFlushWithSoftLimit LogFlushWithSoftLimitTest.cpp)
|
||||
quill_add_test(TEST_MultiFrontendThreads MultiFrontendThreadsTest.cpp)
|
||||
quill_add_test(TEST_MultipleSinksSameLogger MultipleSinksSameLoggerTest.cpp)
|
||||
quill_add_test(TEST_RotatingSinkDailyRotation RotatingSinkDailyRotationTest.cpp)
|
||||
quill_add_test(TEST_RotatingSinkKeepOldest RotatingSinkKeepOldestTest.cpp)
|
||||
quill_add_test(TEST_RotatingSinkOverwriteOldest RotatingSinkOverwriteOldestTest.cpp)
|
||||
quill_add_test(TEST_SignalHandler SignalHandlerTest.cpp)
|
||||
quill_add_test(TEST_SingleFrontendThread SingleFrontendThreadTest.cpp)
|
||||
quill_add_test(TEST_SinkFilter SinkFilterTest.cpp)
|
||||
quill_add_test(TEST_StdArrayLogging StdArrayLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdDequeLogging StdDequeLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdFilesystemPathLogging StdFilesystemPathLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdForwardListLogging StdForwardListLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdListLogging StdListLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdMapLogging StdMapLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdMultiMapLogging StdMultiMapLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdMultiSetLogging StdMultiSetLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdOptionalLogging StdOptionalLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdPairLogging StdPairLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdSetLogging StdSetLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdTupleLogging StdTupleLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdUnorderedMapLogging StdUnorderedMapLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdUnorderedMultiMapLogging StdUnorderedMultiMapLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdUnorderedMultiSetLogging StdUnorderedMultiSetLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdUnorderedSetLogging StdUnorderedSetLoggingTest.cpp)
|
||||
quill_add_test(TEST_StdVectorLogging StdVectorLoggingTest.cpp)
|
||||
quill_add_test(TEST_SinkLogLevelFilter SinkLogLevelFilterTest.cpp)
|
||||
quill_add_test(TEST_StringLargeLogging StringLargeLoggingTest.cpp)
|
||||
quill_add_test(TEST_StringLoggingDynamicLogLevel StringLoggingDynamicLogLevelTest.cpp)
|
||||
quill_add_test(TEST_StringLogging StringLoggingTest.cpp)
|
||||
quill_add_test(TEST_StringRandomLargeLogging StringRandomLargeLoggingTest.cpp)
|
||||
quill_add_test(TEST_StringRandomLogging StringRandomLoggingTest.cpp)
|
||||
quill_add_test(TEST_StringRandomSmallLogging StringRandomSmallLoggingTest.cpp)
|
||||
quill_add_test(TEST_TagsLogging TagsLoggingTest.cpp)
|
||||
quill_add_test(TEST_UserClockSource UserClockSourceTest.cpp)
|
||||
quill_add_test(TEST_UserDefinedTypeLogging UserDefinedTypeLoggingTest.cpp)
|
||||
|
||||
quill_add_test(TEST_CompileActiveLogLevel CompileActiveLogLevelTest.cpp)
|
||||
target_compile_definitions(TEST_CompileActiveLogLevel PRIVATE -DQUILL_COMPILE_ACTIVE_LOG_LEVEL=QUILL_COMPILE_ACTIVE_LOG_LEVEL_WARNING)
|
||||
|
||||
if (WIN32)
|
||||
quill_add_test(TEST_WideStdTypesLogging WideStdTypesLoggingTest.cpp)
|
||||
quill_add_test(TEST_WideStringLogging WideStringLoggingTest.cpp)
|
||||
endif ()
|
|
@ -0,0 +1,67 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("compile_active_log_level")
|
||||
{
|
||||
// we build this target with
|
||||
// add_compile_definitions(-DQUILL_COMPILE_ACTIVE_LOG_LEVEL=QUILL_COMPILE_ACTIVE_LOG_LEVEL_WARNING)
|
||||
static constexpr char const* filename = "compile_active_log_level.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
logger->set_log_level(quill::LogLevel::TraceL3);
|
||||
REQUIRE_EQ(logger->get_log_level(), quill::LogLevel::TraceL3);
|
||||
|
||||
LOG_TRACE_L3(logger, "This is a log trace l3 example {}", 1);
|
||||
LOG_TRACE_L2(logger, "This is a log trace l2 example {} {}", 2, 2.3);
|
||||
LOG_TRACE_L1(logger, "This is a log trace l1 {} example", "string");
|
||||
LOG_DEBUG(logger, "This is a log debug example {}", 4);
|
||||
LOG_INFO(logger, "This is a log info example {}", 21);
|
||||
LOG_WARNING(logger, "This is a log warning example {}", 11);
|
||||
LOG_ERROR(logger, "This is a log error example {}", 3212);
|
||||
LOG_CRITICAL(logger, "This is a log critical example {}", 321);
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check, we only except statements above warning
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), 3);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(file_contents, std::string{"This is a log warning example 11"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(file_contents, std::string{"This is a log error example 3212"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(file_contents, std::string{"This is a log critical example 321"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/bundled/fmt/format.h"
|
||||
#include "quill/bundled/fmt/ranges.h"
|
||||
#include "quill/sinks/ConsoleSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("console_sink_stderr_multiple_formats")
|
||||
{
|
||||
static std::string const logger_name_a = "logger_a";
|
||||
static std::string const logger_name_b = "logger_b";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
quill::testing::CaptureStderr();
|
||||
|
||||
// Set writing logging to a file
|
||||
bool const using_colours = false;
|
||||
std::string const stream = "stderr";
|
||||
auto console_sink = Frontend::create_or_get_sink<ConsoleSink>("console_sink", using_colours, stream);
|
||||
|
||||
Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink);
|
||||
Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink,
|
||||
"%(logger) - %(message) (%(caller_function))");
|
||||
|
||||
console_sink.reset();
|
||||
|
||||
// log a few messages so we rotate files
|
||||
for (size_t i = 0; i < 20; ++i)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
LOG_INFO(logger_a, "Hello log num {}", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO(logger_b, "Hello log num {}", i);
|
||||
}
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// convert result to vector
|
||||
std::string results = quill::testing::GetCapturedStderr();
|
||||
std::stringstream data(results);
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string> result_arr;
|
||||
while (std::getline(data, line, '\n'))
|
||||
{
|
||||
result_arr.push_back(line);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 20; ++i)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
std::string expected_string =
|
||||
"LOG_INFO " + logger_name_a + " Hello log num " + std::to_string(i);
|
||||
|
||||
if (!quill::testing::file_contains(result_arr, expected_string))
|
||||
{
|
||||
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string expected_string =
|
||||
logger_name_b + " - Hello log num " + std::to_string(i) + " (DOCTEST_ANON_FUNC_2)";
|
||||
|
||||
if (!quill::testing::file_contains(result_arr, expected_string))
|
||||
{
|
||||
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/bundled/fmt/format.h"
|
||||
#include "quill/bundled/fmt/ranges.h"
|
||||
#include "quill/sinks/ConsoleSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("console_sink_stdout_multiple_formats")
|
||||
{
|
||||
static std::string const logger_name_a = "logger_a";
|
||||
static std::string const logger_name_b = "logger_b";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
quill::testing::CaptureStdout();
|
||||
|
||||
// Set writing logging to a file
|
||||
bool const using_colours = false;
|
||||
std::string const stream = "stdout";
|
||||
auto console_sink = Frontend::create_or_get_sink<ConsoleSink>("console_sink", using_colours, stream);
|
||||
|
||||
Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink);
|
||||
Logger* logger_b = Frontend::create_or_get_logger(logger_name_b, console_sink,
|
||||
"%(logger) - %(message) (%(caller_function))");
|
||||
|
||||
console_sink.reset();
|
||||
|
||||
// log a few messages so we rotate files
|
||||
for (size_t i = 0; i < 20; ++i)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
LOG_INFO(logger_a, "Hello log num {}", i);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_INFO(logger_b, "Hello log num {}", i);
|
||||
}
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// convert result to vector
|
||||
std::string results = quill::testing::GetCapturedStdout();
|
||||
std::stringstream data(results);
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string> result_arr;
|
||||
while (std::getline(data, line, '\n'))
|
||||
{
|
||||
result_arr.push_back(line);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 20; ++i)
|
||||
{
|
||||
if (i % 2 == 0)
|
||||
{
|
||||
std::string expected_string =
|
||||
"LOG_INFO " + logger_name_a + " Hello log num " + std::to_string(i);
|
||||
|
||||
if (!quill::testing::file_contains(result_arr, expected_string))
|
||||
{
|
||||
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string expected_string =
|
||||
logger_name_b + " - Hello log num " + std::to_string(i) + " (DOCTEST_ANON_FUNC_2)";
|
||||
|
||||
if (!quill::testing::file_contains(result_arr, expected_string))
|
||||
{
|
||||
FAIL(fmtquill::format("expected [{}] is not in results [{}]", expected_string, result_arr).data());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/bundled/fmt/format.h"
|
||||
#include "quill/bundled/fmt/ostream.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
enum TestEnum : int
|
||||
{
|
||||
Test1 = 1,
|
||||
Test2 = 2,
|
||||
Test3 = 3
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, TestEnum const& test_enum)
|
||||
{
|
||||
switch (test_enum)
|
||||
{
|
||||
case TestEnum::Test1:
|
||||
os << "Test1";
|
||||
break;
|
||||
case TestEnum::Test2:
|
||||
os << "Test2";
|
||||
break;
|
||||
case TestEnum::Test3:
|
||||
os << "Test3";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown";
|
||||
break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct fmtquill::formatter<TestEnum> : fmtquill::ostream_formatter
|
||||
{
|
||||
};
|
||||
|
||||
enum class TestEnumClass : uint64_t
|
||||
{
|
||||
Test4 = 4,
|
||||
Test5 = 5,
|
||||
Test6 = 6
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const TestEnumClass& test_enum_class)
|
||||
{
|
||||
switch (test_enum_class)
|
||||
{
|
||||
case TestEnumClass::Test4:
|
||||
os << "Test4";
|
||||
break;
|
||||
case TestEnumClass::Test5:
|
||||
os << "Test5";
|
||||
break;
|
||||
case TestEnumClass::Test6:
|
||||
os << "Test6";
|
||||
break;
|
||||
default:
|
||||
os << "Unknown";
|
||||
break;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
template <>
|
||||
struct fmtquill::formatter<TestEnumClass> : fmtquill::ostream_formatter
|
||||
{
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("enum_logging")
|
||||
{
|
||||
static constexpr char const* filename = "enum_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
LOG_INFO(logger, "{} -> {}, {} -> {}", TestEnum::Test1, static_cast<int>(TestEnum::Test1),
|
||||
TestEnumClass::Test4, static_cast<uint64_t>(TestEnumClass::Test4));
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
std::string expected_string = "LOG_INFO " + logger_name + " Test1 -> 1, Test4 -> 4";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("flush_without_any_log")
|
||||
{
|
||||
static constexpr char const* filename = "flush_without_any_log.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
std::atomic<bool> is_flush_done = false;
|
||||
|
||||
std::thread watcher(
|
||||
[&is_flush_done]()
|
||||
{
|
||||
uint32_t try_count = 2000;
|
||||
while (!is_flush_done.load() && try_count--)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||
}
|
||||
REQUIRE_EQ(is_flush_done.load(), true);
|
||||
});
|
||||
|
||||
logger->flush_log();
|
||||
is_flush_done = true;
|
||||
|
||||
watcher.join();
|
||||
Backend::stop();
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/JsonConsoleSink.h"
|
||||
|
||||
#include "quill/bundled/fmt/format.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("json_console_logging")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 50;
|
||||
static std::string const logger_name_a = "logger_a";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
quill::testing::CaptureStdout();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto console_sink = Frontend::create_or_get_sink<JsonConsoleSink>("json_console");
|
||||
Logger* logger_a = Frontend::create_or_get_logger(logger_name_a, console_sink);
|
||||
|
||||
// log a few messages
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
LOG_INFO(logger_a, "Hello log num [{num}, {multiply}, {add}]", i, i * i, i + i);
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// convert result to vector
|
||||
std::string results = quill::testing::GetCapturedStdout();
|
||||
std::stringstream data(results);
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string> file_contents;
|
||||
while (std::getline(data, line, '\n'))
|
||||
{
|
||||
file_contents.push_back(line);
|
||||
}
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages);
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string const expected_format =
|
||||
R"("logger_a","log_level":"INFO","message":"Hello log num [{{num}}, {{multiply}}, {{add}}]","num":"{}","multiply":"{}","add":"{}")";
|
||||
std::string const expected_string =
|
||||
fmtquill::format(fmtquill::runtime(expected_format), i, i * i, i + i);
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/bundled/fmt/format.h"
|
||||
#include "quill/bundled/fmt/ostream.h"
|
||||
#include "quill/sinks/JsonFileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
class UserDefinedType
|
||||
{
|
||||
public:
|
||||
UserDefinedType() = default;
|
||||
UserDefinedType(size_t i, std::string const& s) : _i(i), _s(s) {}
|
||||
|
||||
virtual ~UserDefinedType() = default;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, UserDefinedType const& obj)
|
||||
{
|
||||
if (obj._i && obj._s)
|
||||
{
|
||||
os << "i: " << *obj._i << ", s: " << *obj._s;
|
||||
}
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<size_t> _i;
|
||||
std::optional<std::string> _s;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct fmtquill::formatter<UserDefinedType> : fmtquill::ostream_formatter
|
||||
{
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("json_file_logging")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 500u;
|
||||
static constexpr size_t number_of_threads = 6;
|
||||
static constexpr char const* json_filename = "json_file_logging.json";
|
||||
static constexpr char const* filename = "json_file_logging_file.log";
|
||||
static std::string const logger_name_prefix = "logger_";
|
||||
|
||||
// Start the logging backend thread
|
||||
BackendOptions bo;
|
||||
bo.error_notifier = [](std::string const&) {};
|
||||
Backend::start(bo);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
threads.emplace_back(
|
||||
[i]() mutable
|
||||
{
|
||||
// log to json
|
||||
auto json_file_sink = Frontend::create_or_get_sink<JsonFileSink>(
|
||||
json_filename,
|
||||
[]()
|
||||
{
|
||||
JsonFileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(
|
||||
logger_name_prefix + std::to_string(i),
|
||||
std::initializer_list<std::shared_ptr<Sink>>{std::move(json_file_sink), std::move(file_sink)},
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) "
|
||||
"%(message) [%(named_args)]");
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// log a message without any args, only from the first thread
|
||||
LOG_INFO(logger, "Hello from thread");
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
LOG_INFO(logger,
|
||||
"Hello from thread {thread_index} this is message {message_num} [{custom}]", i,
|
||||
j, fmtquill::format("{}", UserDefinedType{j, std::to_string(j)}));
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
{
|
||||
// log an invalid format for testing, only from the first thread
|
||||
LOG_INFO(logger, "invalid format [{%f}]", 321.1);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& elem : threads)
|
||||
{
|
||||
elem.join();
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(json_filename);
|
||||
std::vector<std::string> const file_contents_s = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads + 2);
|
||||
REQUIRE_EQ(file_contents_s.size(), number_of_messages * number_of_threads + 2);
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
// for each thread
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
// check json log
|
||||
std::string expected_json_string = std::string{"\"logger\":\""} + logger_name_prefix +
|
||||
std::to_string(i) +
|
||||
std::string{
|
||||
"\",\"log_level\":\"INFO\",\"message\":\"Hello from thread {thread_index} this is "
|
||||
"message {message_num} [{custom}]\","} +
|
||||
std::string{"\"thread_index\":\""} + std::to_string(i) +
|
||||
std::string{"\",\"message_num\":\""} + std::to_string(j) +
|
||||
std::string{"\",\"custom\":\"i: "} + std::to_string(j) + ", s: " + std::to_string(j) +
|
||||
std::string{"\""};
|
||||
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_json_string));
|
||||
|
||||
// check standard log
|
||||
// for each thread [i: 0, s: 0]
|
||||
std::string expected_string = logger_name_prefix + std::to_string(i) +
|
||||
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j) +
|
||||
+" [i: " + std::to_string(j) + ", s: " + std::to_string(j) +
|
||||
"] [thread_index: " + std::to_string(i) + ", message_num: " + std::to_string(j) + ", ";
|
||||
|
||||
REQUIRE(quill::testing::file_contains(file_contents_s, expected_string));
|
||||
}
|
||||
|
||||
std::string expected_no_args_json = "\"log_level\":\"INFO\",\"message\":\"Hello from thread\"";
|
||||
std::string expected_no_args_fmt = "Hello from thread";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_no_args_json));
|
||||
REQUIRE(quill::testing::file_contains(file_contents_s, expected_no_args_fmt));
|
||||
|
||||
std::string expected_invalid_fmt_json =
|
||||
"\"log_level\":\"INFO\",\"message\":\"invalid format [{%f}]\"";
|
||||
std::string expected_invalid_fmt = "invalid format [{%f}]\", location: \"";
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_invalid_fmt_json));
|
||||
REQUIRE(quill::testing::file_contains(file_contents_s, expected_invalid_fmt));
|
||||
}
|
||||
|
||||
testing::remove_file(json_filename);
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("log_arguments_evaluation")
|
||||
{
|
||||
static constexpr char const* filename = "log_arguments_evaluation.log";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
std::string const logger_name = "logger";
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
size_t cnt{0};
|
||||
auto arg_str = [&cnt]()
|
||||
{
|
||||
++cnt;
|
||||
return "expensive_calculation";
|
||||
};
|
||||
|
||||
// 1. checks that log arguments are not evaluated when we don't log
|
||||
logger->set_log_level(quill::LogLevel::Info);
|
||||
LOG_DEBUG(logger, "Test log arguments {}", arg_str());
|
||||
LOG_TRACE_L1(logger, "Test log arguments {}", arg_str());
|
||||
REQUIRE_EQ(cnt, 0);
|
||||
|
||||
// 2. checks that log arguments are evaluated only once per log statement
|
||||
LOG_INFO(logger, "Test log arguments {}", arg_str());
|
||||
REQUIRE_EQ(cnt, 1);
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), 1);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("log_flush_with_soft_limit_test")
|
||||
{
|
||||
static constexpr char const* filename = "log_flush_with_soft_limit_test.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static size_t constexpr soft_limit = 100;
|
||||
|
||||
// make sure we at least x 100 the soft limit to make sure we are testing what we want
|
||||
// to not reduce this number. Increasing is fine
|
||||
static size_t constexpr number_of_messages = soft_limit * 100;
|
||||
static constexpr size_t number_of_threads = 4;
|
||||
|
||||
// When hitting the transit_events_soft_limit several events are processed in the backend at the
|
||||
// same time If all of them are processed there is a chance to miss messages that where in the
|
||||
// queues but never buffered result in example issuing the flush_log() earlier than it should
|
||||
|
||||
// Start the backend thread
|
||||
BackendOptions backend_options;
|
||||
backend_options.transit_events_soft_limit = soft_limit;
|
||||
Backend::start(backend_options);
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
threads.emplace_back(
|
||||
[i]() mutable
|
||||
{
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
cfg.set_do_fsync(true);
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
LOG_INFO(logger, "Hello from thread {} this is message {}", i, j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& elem : threads)
|
||||
{
|
||||
elem.join();
|
||||
}
|
||||
|
||||
Frontend::get_valid_logger()->flush_log();
|
||||
|
||||
// Now check we have all messages in the file after the flush statement
|
||||
|
||||
size_t const total_messages = number_of_messages * number_of_threads;
|
||||
// Read file and check
|
||||
REQUIRE_EQ(testing::file_contents(filename).size(), total_messages);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check again, nothing else was logged
|
||||
REQUIRE_EQ(testing::file_contents(filename).size(), total_messages);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/**
|
||||
* A test class example that is using the logger
|
||||
*/
|
||||
class LoggingTestClass
|
||||
{
|
||||
public:
|
||||
LoggingTestClass(std::string const& filename, std::string const& logger_name)
|
||||
{
|
||||
// create a new logger in the ctor
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
cfg.set_do_fsync(true);
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
quill::Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
~LoggingTestClass()
|
||||
{
|
||||
_logger->flush_log();
|
||||
Frontend::remove_logger(_logger);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use logger in const function
|
||||
*/
|
||||
void use_logger_const() const noexcept { LOG_INFO(_logger, "Test message for test class const"); }
|
||||
|
||||
/**
|
||||
* Use logger in normal function
|
||||
*/
|
||||
void use_logger() const { LOG_INFO(_logger, "Test message for test class non const"); }
|
||||
|
||||
private:
|
||||
quill::Logger* _logger{nullptr};
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("logger_add_remove_get")
|
||||
{
|
||||
// Verifies logging behavior adding, removing and getting loggers
|
||||
// and logging from const member functions while dynamically creating and
|
||||
// removing loggers and reusing the same file after removal.
|
||||
static constexpr size_t iterations = 100;
|
||||
static constexpr char const* filename = "logger_add_remove_get.log";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
for (size_t i = 0; i < iterations; ++i)
|
||||
{
|
||||
std::string const logger_a_name = "logger_a" + std::to_string(i);
|
||||
std::string const logger_b_name = "logger_b" + std::to_string(i);
|
||||
|
||||
{
|
||||
// log for class a
|
||||
LoggingTestClass logging_test_class_a{filename, logger_a_name};
|
||||
logging_test_class_a.use_logger_const();
|
||||
logging_test_class_a.use_logger();
|
||||
|
||||
// log again for class b
|
||||
LoggingTestClass const logging_test_class_b{filename, logger_b_name};
|
||||
logging_test_class_b.use_logger_const();
|
||||
}
|
||||
|
||||
// Test that get_all_loggers() works and also it should be empty after removing the loggers
|
||||
REQUIRE(Frontend::get_all_loggers().empty());
|
||||
REQUIRE(!Frontend::get_logger(logger_a_name));
|
||||
REQUIRE(!Frontend::get_logger(logger_b_name));
|
||||
|
||||
// The only safe way to know that the loggers are really removed is currently this
|
||||
while (Frontend::get_number_of_loggers())
|
||||
{
|
||||
// wait for all the to be removed first by the backend thread first then repeat the test
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
}
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), 3);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
||||
|
||||
Backend::stop();
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("multi_frontend_threads")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 1000;
|
||||
static constexpr size_t number_of_threads = 10;
|
||||
static constexpr char const* filename = "multi_frontend_threads.log";
|
||||
static std::string const logger_name_prefix = "logger_";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
threads.emplace_back(
|
||||
[i]() mutable
|
||||
{
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(
|
||||
logger_name_prefix + std::to_string(i), std::move(file_sink),
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) %(logger:<12) "
|
||||
"%(message)",
|
||||
"%Y-%m-%d %H:%M:%S.%Qns", Timezone::GmtTime, ClockSourceType::System);
|
||||
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
LOG_INFO(logger, "Hello from thread {} this is message {}", i, j);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& elem : threads)
|
||||
{
|
||||
elem.join();
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages * number_of_threads);
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
// for each thread
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
std::string expected_string = logger_name_prefix + std::to_string(i) +
|
||||
" Hello from thread " + std::to_string(i) + " this is message " + std::to_string(j);
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
||||
|
||||
// Check log file is timestamp ordered
|
||||
REQUIRE(quill::testing::is_timestamp_ordered(file_contents));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/ConsoleSink.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("multiple_sinks_same_logger")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 10000;
|
||||
static constexpr char const* filename = "multiple_sinks_same_logger.log";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
quill::testing::CaptureStdout();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
bool const using_colours = false;
|
||||
std::string const stream = "stdout";
|
||||
auto console_sink = Frontend::create_or_get_sink<ConsoleSink>("console_sink", using_colours, stream);
|
||||
|
||||
std::string const logger_name = "logger";
|
||||
Logger* logger =
|
||||
Frontend::create_or_get_logger(logger_name, {std::move(file_sink), std::move(console_sink)});
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
LOG_INFO(logger, "This is message {}", i);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
{
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages);
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string expected_string = logger_name + " This is message " + std::to_string(i);
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// convert stdout result to vector
|
||||
std::string results = quill::testing::GetCapturedStdout();
|
||||
std::stringstream data(results);
|
||||
|
||||
std::string line;
|
||||
std::vector<std::string> file_contents;
|
||||
while (std::getline(data, line, '\n'))
|
||||
{
|
||||
file_contents.push_back(line);
|
||||
}
|
||||
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages);
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string expected_string = "logger This is message " + std::to_string(i);
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/RotatingFileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("rotating_sink_daily_rotation")
|
||||
{
|
||||
// This test has 2 loggers that they logged to different rotating file handlers
|
||||
static char const* base_filename = "rotating_sink_daily_rotation.log";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Create a rotating file handler
|
||||
std::shared_ptr<quill::Sink> rotating_file_sink_a =
|
||||
Frontend::create_or_get_sink<RotatingFileSink>(base_filename,
|
||||
[]()
|
||||
{
|
||||
RotatingFileSinkConfig rfh_cfg;
|
||||
rfh_cfg.set_rotation_time_daily("00:00");
|
||||
rfh_cfg.set_open_mode('w');
|
||||
return rfh_cfg;
|
||||
}());
|
||||
|
||||
// Get the same instance back - we search it again (for testing only)
|
||||
quill::Logger* logger = Frontend::create_or_get_logger("logger", std::move(rotating_file_sink_a));
|
||||
|
||||
// log a few messages so we rotate files
|
||||
for (uint32_t i = 0; i < 20; ++i)
|
||||
{
|
||||
LOG_INFO(logger, "Hello daily file log num {}", i);
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(base_filename);
|
||||
REQUIRE_EQ(file_contents.size(), 20);
|
||||
|
||||
testing::remove_file(base_filename);
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/RotatingFileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("rotating_sink_keep_oldest")
|
||||
{
|
||||
// This test has 2 loggers that they logged to different rotating file handlers
|
||||
static char const* base_filename_a = "rotating_sink_keep_oldest_a.log";
|
||||
static constexpr char const* base_filename_a_1 = "rotating_sink_keep_oldest_a.1.log";
|
||||
static constexpr char const* base_filename_a_2 = "rotating_sink_keep_oldest_a.2.log";
|
||||
|
||||
static char const* base_filename_b = "rotating_sink_keep_oldest_b.log";
|
||||
static constexpr char const* base_filename_b_1 = "rotating_sink_keep_oldest_b.1.log";
|
||||
|
||||
static constexpr size_t max_file_size = 900;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Create a rotating file handler
|
||||
std::shared_ptr<quill::Sink> rotating_file_sink_a =
|
||||
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_a,
|
||||
[]()
|
||||
{
|
||||
RotatingFileSinkConfig rfh_cfg;
|
||||
rfh_cfg.set_rotation_max_file_size(max_file_size);
|
||||
rfh_cfg.set_max_backup_files(2);
|
||||
rfh_cfg.set_overwrite_rolled_files(false);
|
||||
rfh_cfg.set_open_mode('w');
|
||||
return rfh_cfg;
|
||||
}());
|
||||
|
||||
// Get the same instance back - we search it again (for testing only)
|
||||
quill::Logger* logger_a = Frontend::create_or_get_logger("logger_a", std::move(rotating_file_sink_a));
|
||||
|
||||
// Another rotating logger to another file with max backup count 1 this time. Here we rotate only once
|
||||
std::shared_ptr<quill::Sink> rotating_file_sink_b =
|
||||
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_b,
|
||||
[]()
|
||||
{
|
||||
RotatingFileSinkConfig rfh_cfg;
|
||||
rfh_cfg.set_rotation_max_file_size(max_file_size);
|
||||
rfh_cfg.set_max_backup_files(1);
|
||||
rfh_cfg.set_overwrite_rolled_files(false);
|
||||
rfh_cfg.set_open_mode('w');
|
||||
return rfh_cfg;
|
||||
}());
|
||||
|
||||
quill::Logger* logger_b = Frontend::create_or_get_logger("logger_b", std::move(rotating_file_sink_b));
|
||||
|
||||
// log a few messages so we rotate files
|
||||
for (uint32_t i = 0; i < 20; ++i)
|
||||
{
|
||||
LOG_INFO(logger_a, "Hello rotating file log num {}", i);
|
||||
LOG_INFO(logger_b, "Hello rotating file log num {}", i);
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(base_filename_a);
|
||||
REQUIRE_GE(file_contents.size(), 3);
|
||||
|
||||
std::vector<std::string> const file_contents_1 = quill::testing::file_contents(base_filename_a_1);
|
||||
REQUIRE_GE(file_contents_1.size(), 7);
|
||||
|
||||
std::vector<std::string> const file_contents_2 = quill::testing::file_contents(base_filename_a_2);
|
||||
REQUIRE_GE(file_contents_2.size(), 7);
|
||||
|
||||
// File from 2nd logger
|
||||
std::vector<std::string> const file_contents_3 = quill::testing::file_contents(base_filename_b);
|
||||
REQUIRE_GE(file_contents_3.size(), 11);
|
||||
|
||||
std::vector<std::string> const file_contents_4 = quill::testing::file_contents(base_filename_b_1);
|
||||
REQUIRE_GE(file_contents_4.size(), 7);
|
||||
|
||||
// Remove filenames
|
||||
testing::remove_file(base_filename_a);
|
||||
testing::remove_file(base_filename_a_1);
|
||||
testing::remove_file(base_filename_a_2);
|
||||
testing::remove_file(base_filename_b);
|
||||
testing::remove_file(base_filename_b_1);
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/RotatingFileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("rotating_sink_overwrite_oldest")
|
||||
{
|
||||
// This test has 2 loggers that they logged to different rotating file handlers
|
||||
static char const* base_filename_a = "rotating_sink_overwrite_oldest_a.log";
|
||||
static constexpr char const* base_filename_a_1 = "rotating_sink_overwrite_oldest_a.1.log";
|
||||
static constexpr char const* base_filename_a_2 = "rotating_sink_overwrite_oldest_a.2.log";
|
||||
|
||||
static char const* base_filename_b = "rotating_sink_overwrite_oldest_b.log";
|
||||
static constexpr char const* base_filename_b_1 = "rotating_sink_overwrite_oldest_b.1.log";
|
||||
|
||||
static constexpr size_t max_file_size = 900;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Create a rotating file handler
|
||||
std::shared_ptr<quill::Sink> rotating_file_sink_a =
|
||||
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_a,
|
||||
[]()
|
||||
{
|
||||
RotatingFileSinkConfig rfh_cfg;
|
||||
rfh_cfg.set_rotation_max_file_size(max_file_size);
|
||||
rfh_cfg.set_max_backup_files(2);
|
||||
rfh_cfg.set_overwrite_rolled_files(true);
|
||||
rfh_cfg.set_open_mode('w');
|
||||
return rfh_cfg;
|
||||
}());
|
||||
|
||||
// Get the same instance back - we search it again (for testing only)
|
||||
quill::Logger* logger_a = Frontend::create_or_get_logger("logger_a", std::move(rotating_file_sink_a));
|
||||
|
||||
// Another rotating logger to another file with max backup count 1 this time. Here we rotate only once
|
||||
std::shared_ptr<quill::Sink> rotating_file_sink_b =
|
||||
Frontend::create_or_get_sink<RotatingFileSink>(base_filename_b,
|
||||
[]()
|
||||
{
|
||||
RotatingFileSinkConfig rfh_cfg;
|
||||
rfh_cfg.set_rotation_max_file_size(max_file_size);
|
||||
rfh_cfg.set_max_backup_files(1);
|
||||
rfh_cfg.set_overwrite_rolled_files(true);
|
||||
rfh_cfg.set_open_mode('w');
|
||||
return rfh_cfg;
|
||||
}());
|
||||
|
||||
quill::Logger* logger_b = Frontend::create_or_get_logger("logger_b", std::move(rotating_file_sink_b));
|
||||
|
||||
// log a few messages so we rotate files
|
||||
for (uint32_t i = 0; i < 20; ++i)
|
||||
{
|
||||
LOG_INFO(logger_a, "Hello rotating file log num {}", i);
|
||||
LOG_INFO(logger_b, "Hello rotating file log num {}", i);
|
||||
}
|
||||
|
||||
// flush all log and remove all loggers
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(base_filename_a);
|
||||
REQUIRE_GE(file_contents.size(), 3);
|
||||
|
||||
std::vector<std::string> const file_contents_1 = quill::testing::file_contents(base_filename_a_1);
|
||||
REQUIRE_GE(file_contents_1.size(), 7);
|
||||
|
||||
std::vector<std::string> const file_contents_2 = quill::testing::file_contents(base_filename_a_2);
|
||||
REQUIRE_GE(file_contents_2.size(), 7);
|
||||
|
||||
// File from 2nd logger
|
||||
std::vector<std::string> const file_contents_3 = quill::testing::file_contents(base_filename_b);
|
||||
REQUIRE_GE(file_contents_3.size(), 4);
|
||||
|
||||
std::vector<std::string> const file_contents_4 = quill::testing::file_contents(base_filename_b_1);
|
||||
REQUIRE_GE(file_contents_4.size(), 7);
|
||||
|
||||
// Remove filenames
|
||||
testing::remove_file(base_filename_a);
|
||||
testing::remove_file(base_filename_a_1);
|
||||
testing::remove_file(base_filename_a_2);
|
||||
testing::remove_file(base_filename_b);
|
||||
testing::remove_file(base_filename_b_1);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("signal_handler")
|
||||
{
|
||||
static constexpr char const* filename = "signal_handler.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_messages = 10;
|
||||
static constexpr size_t number_of_threads = 10;
|
||||
static std::string const logger_name_prefix = "logger_";
|
||||
|
||||
// Start the logging backend thread, we expect the signal handler to catch the signal,
|
||||
// flush the log and raise the signal back
|
||||
Backend::start_with_signal_handler<FrontendOptions>(BackendOptions{},
|
||||
std::initializer_list<int>{SIGABRT}, 40);
|
||||
|
||||
// For testing purposes we want to keep the application running, we do not reraise the signal
|
||||
detail::SignalHandlerContext::instance().should_reraise_signal.store(false);
|
||||
|
||||
quill::Frontend::preallocate();
|
||||
|
||||
std::vector<std::thread> threads;
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
threads.emplace_back(
|
||||
[i]() mutable
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
// NOTE: On windows the signal handler must be installed on each new thread
|
||||
quill::init_signal_handler<quill::FrontendOptions>();
|
||||
#endif
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
cfg.set_do_fsync(true);
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger =
|
||||
Frontend::create_or_get_logger(logger_name_prefix + std::to_string(i), std::move(file_sink));
|
||||
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
LOG_INFO(logger, "{} {} {}", i, j,
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
|
||||
"incididunt ut labore et dolore magna aliqua.");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
for (auto& elem : threads)
|
||||
{
|
||||
elem.join();
|
||||
}
|
||||
|
||||
// Now raise a signal
|
||||
std::raise(SIGABRT);
|
||||
|
||||
{
|
||||
// Except the log and the signal handler in the logs
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
for (size_t i = 0; i < number_of_threads; ++i)
|
||||
{
|
||||
// for each thread
|
||||
for (size_t j = 0; j < number_of_messages; ++j)
|
||||
{
|
||||
std::string expected_string = logger_name_prefix + std::to_string(i) + " " +
|
||||
std::to_string(i) + " " + std::to_string(j) +
|
||||
" Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
|
||||
"incididunt ut labore et dolore magna aliqua.";
|
||||
|
||||
REQUIRE(testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
REQUIRE(quill::testing::file_contains(file_contents, std::string{"Received signal: 22 (signum: 22)"}));
|
||||
#elif defined(__apple_build_version__)
|
||||
REQUIRE(quill::testing::file_contains(file_contents, std::string{"Received signal: Abort trap: 6 (signum: 6)"}));
|
||||
#else
|
||||
REQUIRE(quill::testing::file_contains(file_contents, std::string{"Received signal: Aborted (signum: 6)"}));
|
||||
#endif
|
||||
}
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
for (Logger* logger : Frontend::get_all_loggers())
|
||||
{
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
}
|
||||
|
||||
Backend::stop();
|
||||
REQUIRE_FALSE(Backend::is_running());
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("single_frontend_thread")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 10000;
|
||||
static constexpr char const* filename = "single_frontend_thread.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
LOG_INFO(logger, "This is message {}", i);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages);
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string expected_string = logger_name + " This is message " + std::to_string(i);
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/**
|
||||
* Filter class for our file handler
|
||||
*/
|
||||
class FileFilterA : public Filter
|
||||
{
|
||||
public:
|
||||
FileFilterA() : Filter("FileFilterA") {}
|
||||
|
||||
QUILL_NODISCARD bool filter(MacroMetadata const* log_metadata, uint64_t log_timestamp, std::string_view thread_id,
|
||||
std::string_view thread_name, std::string_view logger_name,
|
||||
LogLevel log_level, std::string_view log_message) noexcept override
|
||||
{
|
||||
if (log_metadata->log_level() < LogLevel::Warning)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Filter for the stdout handler
|
||||
*/
|
||||
class FileFilterB : public Filter
|
||||
{
|
||||
public:
|
||||
FileFilterB() : Filter("FileFilterB") {}
|
||||
|
||||
QUILL_NODISCARD bool filter(MacroMetadata const* log_metadata, uint64_t log_timestamp, std::string_view thread_id,
|
||||
std::string_view thread_name, std::string_view logger_name,
|
||||
LogLevel log_level, std::string_view log_message) noexcept override
|
||||
{
|
||||
if (log_metadata->log_level() >= LogLevel::Warning)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("sink_filter")
|
||||
{
|
||||
static constexpr char const* filename_a = "sink_filter_a.log";
|
||||
static constexpr char const* filename_b = "sink_filter_b.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink_a = Frontend::create_or_get_sink<FileSink>(
|
||||
filename_a,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// log to filename_a anything below warning
|
||||
std::unique_ptr<Filter> filter_a = std::make_unique<FileFilterA>();
|
||||
|
||||
// Also test get_filter_name()
|
||||
REQUIRE_EQ(filter_a->get_filter_name(), std::string_view{"FileFilterA"});
|
||||
|
||||
// Add the filter
|
||||
file_sink_a->add_filter(std::move(filter_a));
|
||||
|
||||
// Try to add the same again (same name)
|
||||
std::unique_ptr<Filter> filter_a_2 = std::make_unique<FileFilterA>();
|
||||
REQUIRE_EQ(filter_a_2->get_filter_name(), std::string_view{"FileFilterA"});
|
||||
REQUIRE_THROWS_AS(file_sink_a->add_filter(std::move(filter_a_2)), QuillError);
|
||||
|
||||
auto file_sink_b = Frontend::create_or_get_sink<FileSink>(
|
||||
filename_b,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// log to filename_b warning, error, critical
|
||||
file_sink_b->add_filter(std::make_unique<FileFilterB>());
|
||||
|
||||
Logger* logger =
|
||||
Frontend::create_or_get_logger(logger_name, {std::move(file_sink_a), std::move(file_sink_b)});
|
||||
|
||||
LOG_INFO(logger, "Lorem ipsum dolor sit amet, consectetur adipiscing elit");
|
||||
LOG_ERROR(logger, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante");
|
||||
|
||||
// Let all log get flushed to the file
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents_a = quill::testing::file_contents(filename_a);
|
||||
REQUIRE_EQ(file_contents_a.size(), 1);
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents_a,
|
||||
std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur adipiscing elit"}));
|
||||
|
||||
std::vector<std::string> const file_contents_b = quill::testing::file_contents(filename_b);
|
||||
REQUIRE_EQ(file_contents_b.size(), 1);
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents_b,
|
||||
std::string{"LOG_ERROR " + logger_name +
|
||||
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante"}));
|
||||
|
||||
testing::remove_file(filename_a);
|
||||
testing::remove_file(filename_b);
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("sink_log_level_filter")
|
||||
{
|
||||
static constexpr char const* filename_a = "sink_log_level_filter_a.log";
|
||||
static constexpr char const* filename_b = "sink_log_level_filter_b.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink_a = Frontend::create_or_get_sink<FileSink>(
|
||||
filename_a,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// Set filters to our handlers
|
||||
REQUIRE_EQ(file_sink_a->get_log_level_filter(), LogLevel::TraceL3);
|
||||
file_sink_a->set_log_level_filter(LogLevel::Info);
|
||||
REQUIRE_EQ(file_sink_a->get_log_level_filter(), LogLevel::Info);
|
||||
|
||||
auto file_sink_b = Frontend::create_or_get_sink<FileSink>(
|
||||
filename_b,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// log to filename_b warning, error, critical
|
||||
REQUIRE_EQ(file_sink_b->get_log_level_filter(), LogLevel::TraceL3);
|
||||
file_sink_b->set_log_level_filter(LogLevel::Error);
|
||||
REQUIRE_EQ(file_sink_b->get_log_level_filter(), LogLevel::Error);
|
||||
|
||||
Logger* logger =
|
||||
Frontend::create_or_get_logger(logger_name, {std::move(file_sink_a), std::move(file_sink_b)});
|
||||
|
||||
LOG_INFO(logger, "Lorem ipsum dolor sit amet, consectetur adipiscing elit");
|
||||
LOG_ERROR(logger, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante");
|
||||
|
||||
// Let all log get flushed to the file
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents_a = quill::testing::file_contents(filename_a);
|
||||
REQUIRE_EQ(file_contents_a.size(), 2);
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents_a,
|
||||
std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur adipiscing elit"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents_a,
|
||||
std::string{"LOG_ERROR " + logger_name +
|
||||
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante"}));
|
||||
|
||||
std::vector<std::string> const file_contents_b = quill::testing::file_contents(filename_b);
|
||||
REQUIRE_EQ(file_contents_b.size(), 1);
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents_b,
|
||||
std::string{"LOG_ERROR " + logger_name +
|
||||
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante"}));
|
||||
|
||||
testing::remove_file(filename_a);
|
||||
testing::remove_file(filename_b);
|
||||
}
|
|
@ -0,0 +1,209 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Array.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_array_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_array_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::array<bool, 2> b = {true, false};
|
||||
LOG_INFO(logger, "v {}", b);
|
||||
|
||||
std::array<char, 2> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::array<short, 2> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::array<int, 2> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::array<long, 2> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::array<long long, 2> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::array<unsigned short, 2> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::array<unsigned int, 2> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::array<unsigned long, 2> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::array<unsigned long long, 2> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::array<float, 2> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::array<double, 2> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::array<int, 2> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::array<int, 2>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::array<std::string, 2> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::array<std::string_view, 2> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::array<char const*, 4> scva = {"c style", "string test", "test", "log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::array<std::array<int, 2>, 3> aai = {{{321, 123}, {444, 333}, {111, 222}}};
|
||||
LOG_INFO(logger, "aai {}", aai);
|
||||
|
||||
std::array<std::array<char const*, 2>, 3> aacs = {
|
||||
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
|
||||
LOG_INFO(logger, "aacs {}", aacs);
|
||||
|
||||
std::array<std::array<std::array<char const*, 2>, 2>, 3> aaacs = {
|
||||
{{{{"one", "two"}, {"three", "four"}}},
|
||||
{{{"five", "six"}, {"seven", "eight"}}},
|
||||
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaacs {}", aaacs);
|
||||
|
||||
std::array<std::array<std::array<std::string, 2>, 2>, 3> aaabcs = {
|
||||
{{{{"std_one", "two"}, {"three", "four"}}},
|
||||
{{{"five", "six"}, {"seven", "eight"}}},
|
||||
{{{"std_nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaabcs {}", aaabcs);
|
||||
|
||||
std::array<std::array<std::array<std::string_view, 2>, 2>, 3> aaaccs = {
|
||||
{{{{"std_one", "two"}, {"three_std", "four"}}},
|
||||
{{{"five", "six"}, {"seven_std", "eight"}}},
|
||||
{{{"std_nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaaccs {}", aaaccs);
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aaacs {} aai {}", scva, sa, ulli, scva, sa, aaacs, aai);
|
||||
|
||||
std::array<int, 4> empt{};
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " v [true, false]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aai [[321, 123], [444, 333], [111, 222]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" aacs [[\"one\", \"two\"], [\"three\", \"four\"], [\"five\", \"six\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaabcs [[[\"std_one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaaccs [[[\"std_one\", \"two\"], [\"three_std\", \"four\"]], [[\"five\", \"six\"], [\"seven_std\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]] aai [[321, 123], [444, 333], [111, 222]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt [0, 0, 0, 0]"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Deque.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_deque_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_deque_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::deque<char> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::deque<short> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::deque<int> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::deque<long> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::deque<long long> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::deque<unsigned short> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::deque<unsigned int> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::deque<unsigned long> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::deque<unsigned long long> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::deque<float> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::deque<double> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::deque<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::deque<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::deque<std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::deque<std::string_view> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::deque<char const*> scva = {"c style", "string test", "test", "log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::deque<std::deque<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
|
||||
LOG_INFO(logger, "aai {}", aai);
|
||||
|
||||
std::deque<std::deque<char const*>> aacs = {
|
||||
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
|
||||
LOG_INFO(logger, "aacs {}", aacs);
|
||||
|
||||
std::deque<std::deque<std::deque<char const*>>> aaacs = {
|
||||
{{{{"one", "two"}, {"three", "four"}}},
|
||||
{{{"five", "six"}, {"seven", "eight"}}},
|
||||
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaacs {}", aaacs);
|
||||
|
||||
{
|
||||
std::deque<std::deque<std::deque<std::string>>> aaabcs;
|
||||
|
||||
// First outer deque
|
||||
std::deque<std::deque<std::string>> first_outer = {{"std_one", "two"}, {"three", "four"}};
|
||||
|
||||
// Second outer deque
|
||||
std::deque<std::deque<std::string>> second_outer = {{"five", "six"}, {"seven", "eight"}};
|
||||
|
||||
// Third outer deque
|
||||
std::deque<std::deque<std::string>> third_outer = {{"std_nine", "ten"}, {"eleven", "twelve"}};
|
||||
|
||||
aaabcs.push_back(first_outer);
|
||||
aaabcs.push_back(second_outer);
|
||||
aaabcs.push_back(third_outer);
|
||||
|
||||
LOG_INFO(logger, "aaabcs {}", aaabcs);
|
||||
}
|
||||
|
||||
{
|
||||
std::deque<std::deque<std::deque<std::string>>> aaaccs;
|
||||
|
||||
// First outer deque
|
||||
std::deque<std::deque<std::string>> first_outer = {{"std_one", "two"}, {"three_std", "four"}};
|
||||
|
||||
// Second outer deque
|
||||
std::deque<std::deque<std::string>> second_outer = {{"five", "six"}, {"seven_std", "eight"}};
|
||||
|
||||
// Third outer deque
|
||||
std::deque<std::deque<std::string>> third_outer = {{"std_nine", "ten"}, {"eleven", "twelve"}};
|
||||
|
||||
aaaccs.push_back(first_outer);
|
||||
aaaccs.push_back(second_outer);
|
||||
aaaccs.push_back(third_outer);
|
||||
|
||||
LOG_INFO(logger, "aaaccs {}", aaaccs);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aaacs {} aai {}", scva, sa, ulli, scva, sa, aaacs, aai);
|
||||
|
||||
std::deque<int> loopv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopv.push_back(iter);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::deque<std::string> loopsv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopsv.push_back(std::to_string(iter));
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopsv {}", loopsv);
|
||||
|
||||
std::deque<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aai [[321, 123], [444, 333], [111, 222]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" aacs [[\"one\", \"two\"], [\"three\", \"four\"], [\"five\", \"six\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaabcs [[[\"std_one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaaccs [[[\"std_one\", \"two\"], [\"three_std\", \"four\"]], [[\"five\", \"six\"], [\"seven_std\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]] aai [[321, 123], [444, 333], [111, 222]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/core/Filesystem.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include "quill/std/FilesystemPath.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_filesystem_path_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_filesystem_path_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
fs::path sp{"/usr/local/bin"};
|
||||
LOG_INFO(logger, "sp {} {} {}", sp, sp, sp);
|
||||
LOG_INFO(logger, "sp_2 {} {} {}", sp, sp, sp);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sp /usr/local/bin /usr/local/bin /usr/local/bin"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sp_2 /usr/local/bin /usr/local/bin /usr/local/bin"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/ForwardList.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <forward_list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_forward_list_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_forward_list_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::forward_list<char> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::forward_list<short> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::forward_list<int> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::forward_list<long> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::forward_list<long long> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::forward_list<unsigned short> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::forward_list<unsigned int> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::forward_list<unsigned long> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::forward_list<unsigned long long> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::forward_list<float> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::forward_list<double> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::forward_list<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::forward_list<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::forward_list<std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::forward_list<std::string_view> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::forward_list<char const*> scva = {"c style", "string test", "test", "log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
|
||||
|
||||
std::forward_list<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/List.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_list_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_list_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::list<char> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::list<short> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::list<int> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::list<long> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::list<long long> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::list<unsigned short> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::list<unsigned int> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::list<unsigned long> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::list<unsigned long long> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::list<float> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::list<double> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::list<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::list<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::list<std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::list<std::string_view> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::list<char const*> scva = {"c style", "string test", "test", "log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
|
||||
|
||||
std::list<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Map.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
struct CStringComparator
|
||||
{
|
||||
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_map_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_map_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::map<int, double> idm = {{111, 3213.21}, {222, 321.19}, {333, 5555.99}};
|
||||
LOG_INFO(logger, "idm {}", idm);
|
||||
|
||||
std::map<int, std::string> loopv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopv.emplace(iter, std::to_string(iter));
|
||||
}
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::map<std::string, std::string> loopsv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
|
||||
}
|
||||
LOG_INFO(logger, "loopsv {}", loopv);
|
||||
|
||||
std::map<char const*, char const*, CStringComparator> ccm = {
|
||||
{"4", "400"}, {"3", "300"}, {"1", "100"}, {"2", "200"}};
|
||||
LOG_INFO(logger, "ccm {}", ccm);
|
||||
|
||||
std::map<char const*, int, CStringComparator> cim = {{"4", 4}, {"3", 3}, {"1", 1}, {"2", 2}};
|
||||
LOG_INFO(logger, "cim {}", cim);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21, 222: 321.19, 333: 5555.99}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\""}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" ccm {\"1\": \"100\", \"2\": \"200\", \"3\": \"300\", \"4\": \"400\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"1\": 1, \"2\": 2, \"3\": 3, \"4\": 4}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Map.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
struct CStringComparator
|
||||
{
|
||||
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_multimap_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_multimap_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::multimap<int, double> idm = {{111, 3213.21}, {222, 321.19}, {333, 5555.99}};
|
||||
LOG_INFO(logger, "idm {}", idm);
|
||||
|
||||
std::multimap<int, std::string> loopv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopv.emplace(iter, std::to_string(iter));
|
||||
}
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::multimap<std::string, std::string> loopsv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
|
||||
}
|
||||
LOG_INFO(logger, "loopsv {}", loopv);
|
||||
|
||||
std::multimap<char const*, char const*, CStringComparator> ccm = {
|
||||
{"4", "400"}, {"3", "300"}, {"1", "100"}, {"2", "200"}};
|
||||
LOG_INFO(logger, "ccm {}", ccm);
|
||||
|
||||
std::multimap<char const*, int, CStringComparator> cim = {{"4", 4}, {"3", 3}, {"1", 1}, {"2", 2}};
|
||||
LOG_INFO(logger, "cim {}", cim);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21, 222: 321.19, 333: 5555.99}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {0: \"0\", 1: \"1\", 2: \"2\", 3: \"3\", 4: \"4\", 5: \"5\", 6: \"6\", 7: \"7\", 8: \"8\", 9: \"9\", 10: \"10\", 11: \"11\", 12: \"12\", 13: \"13\", 14: \"14\", 15: \"15\", 16: \"16\", 17: \"17\", 18: \"18\", 19: \"19\", 20: \"20\", 21: \"21\", 22: \"22\", 23: \"23\", 24: \"24\""}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" ccm {\"1\": \"100\", \"2\": \"200\", \"3\": \"300\", \"4\": \"400\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"1\": 1, \"2\": 2, \"3\": 3, \"4\": 4}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,218 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Set.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
struct CStringComparator
|
||||
{
|
||||
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_multiset_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_multiset_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::multiset<char> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::multiset<short> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::multiset<int> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::multiset<long> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::multiset<long long> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::multiset<unsigned short> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::multiset<unsigned int> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::multiset<unsigned long> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::multiset<unsigned long long> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::multiset<float> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::multiset<double> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::multiset<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::multiset<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::multiset<std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::multiset<std::string_view> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::multiset<char const*, CStringComparator> scva = {"c_style", "aa", "string_test", "test",
|
||||
"log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::multiset<std::multiset<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
|
||||
LOG_INFO(logger, "aai {}", aai);
|
||||
|
||||
{
|
||||
std::multiset<std::multiset<char const*, CStringComparator>> aacs = {
|
||||
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
|
||||
LOG_INFO(logger, "aacs {}", aacs);
|
||||
}
|
||||
|
||||
{
|
||||
std::multiset<std::multiset<std::multiset<char const*, CStringComparator>>> aaacs = {
|
||||
{{{{"one", "two"}, {"three", "four"}}},
|
||||
{{{"five", "six"}, {"seven", "eight"}}},
|
||||
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaacs {}", aaacs);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aai {}", scva, sa, ulli, scva, sa, aai);
|
||||
|
||||
std::multiset<int> loopv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopv.insert(iter);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::multiset<std::string> loopsv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopsv.insert(std::to_string(iter));
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopsv {}", loopsv);
|
||||
|
||||
std::multiset<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a', 'c'}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12, 10}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123, 1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li {1232, 9876}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli {231, 321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi {2, 15}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui {2, 123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli {2876, 3213}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321, 1321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1, 323.31}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1, 3213213.123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123, 1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123, 1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"string\", \"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\", \"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aai {{111, 222}, {123, 321}, {333, 444}}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aacs {{"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs {{{"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} ulli {321, 1321} scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} aai {{111, 222}, {123, 321}, {333, 444}}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {\"0\", \"1\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"2\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"3\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"4\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"5\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"6\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"7\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"8\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"9\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include "quill/std/Optional.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_optional_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_optional_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::optional<int> ei{std::nullopt};
|
||||
LOG_INFO(logger, "ei [{}]", ei);
|
||||
|
||||
std::optional<double> ed{std::nullopt};
|
||||
LOG_INFO(logger, "ed [{}]", ed);
|
||||
|
||||
std::optional<char const*> ccp{"testing"};
|
||||
LOG_INFO(logger, "ccp [{}]", ccp);
|
||||
|
||||
std::optional<std::string> sp{"sp_testing"};
|
||||
LOG_INFO(logger, "sp [{}]", sp);
|
||||
|
||||
std::optional<std::string> esp{std::nullopt};
|
||||
LOG_INFO(logger, "esp [{}]", esp);
|
||||
|
||||
std::optional<std::string_view> svp{"svp_testing"};
|
||||
LOG_INFO(logger, "svp [{}]", svp);
|
||||
|
||||
std::optional<int> i{123321};
|
||||
LOG_INFO(logger, "i [{}]", i);
|
||||
|
||||
std::optional<double> d{333.221};
|
||||
LOG_INFO(logger, "d [{}]", d);
|
||||
|
||||
LOG_INFO(logger, "zzzz [{}] [{}] [{}] [{}] [{}]", d, "test", *svp, *sp, ccp);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ei [none]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ed [none]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccp [optional(\"testing\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sp [optional(\"sp_testing\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " esp [none]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " svp [optional(\"svp_testing\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [optional(123321)]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [optional(333.221)]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " zzzz [optional(333.221)] [test] [svp_testing] [sp_testing] [optional(\"testing\")]"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include "quill/std/Pair.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_pair_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_pair_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::pair<bool, int> b = {true, 312};
|
||||
LOG_INFO(logger, "v {}", b);
|
||||
|
||||
std::pair<std::string, std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::pair<std::string_view, std::string> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::pair<char const*, std::string> scva = {"c style", "string test"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::pair<std::pair<std::string, std::string_view>, std::pair<const char*, uint32_t>> cp = {
|
||||
{"pair", "testing"}, {"first", 2}};
|
||||
LOG_INFO(logger, "cp {}", cp);
|
||||
|
||||
std::pair<int, double> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " v (true, 312)"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa (\"test\", \"string\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva (\"test\", \"string_view\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva (\"c style\", \"string test\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cp ((\"pair\", \"testing\"), (\"first\", 2))"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt (0, 0)"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,217 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Set.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
struct CStringComparator
|
||||
{
|
||||
bool operator()(char const* a, char const* b) const { return std::strcmp(a, b) < 0; }
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_set_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_set_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::set<char> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::set<short> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::set<int> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::set<long> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::set<long long> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::set<unsigned short> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::set<unsigned int> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::set<unsigned long> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::set<unsigned long long> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::set<float> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::set<double> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::set<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::set<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::set<std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::set<std::string_view> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::set<char const*, CStringComparator> scva = {"c_style", "aa", "string_test", "test", "log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::set<std::set<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
|
||||
LOG_INFO(logger, "aai {}", aai);
|
||||
|
||||
{
|
||||
std::set<std::set<char const*, CStringComparator>> aacs = {
|
||||
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
|
||||
LOG_INFO(logger, "aacs {}", aacs);
|
||||
}
|
||||
|
||||
{
|
||||
std::set<std::set<std::set<char const*, CStringComparator>>> aaacs = {
|
||||
{{{{"one", "two"}, {"three", "four"}}},
|
||||
{{{"five", "six"}, {"seven", "eight"}}},
|
||||
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaacs {}", aaacs);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aai {}", scva, sa, ulli, scva, sa, aai);
|
||||
|
||||
std::set<int> loopv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopv.insert(iter);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::set<std::string> loopsv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopsv.insert(std::to_string(iter));
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopsv {}", loopsv);
|
||||
|
||||
std::set<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a', 'c'}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12, 10}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123, 1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li {1232, 9876}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli {231, 321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi {2, 15}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui {2, 123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli {2876, 3213}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321, 1321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1, 323.31}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1, 3213213.123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123, 1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123, 1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"string\", \"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\", \"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aai {{111, 222}, {123, 321}, {333, 444}}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aacs {{"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs {{{"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} ulli {321, 1321} scva {\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"} sa {\"string\", \"test\"} aai {{111, 222}, {123, 321}, {333, 444}}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {\"0\", \"1\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"2\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"3\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"4\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"5\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"6\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"7\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"8\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"9\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include "quill/std/Tuple.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_tuple_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_tuple_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::tuple<std::string> st{"123456789"};
|
||||
LOG_INFO(logger, "st {}", st);
|
||||
|
||||
std::tuple<std::string, int> et;
|
||||
LOG_INFO(logger, "et {}", et);
|
||||
|
||||
std::tuple<std::string, std::string_view, int, double, char const*, std::string, int> ct{
|
||||
"string", "string_view", 213, 33.12, "c_style", "another_string", 123};
|
||||
LOG_INFO(logger, "ct {}", ct);
|
||||
|
||||
LOG_INFO(logger, "ct {} et {} st {}", ct, et, st);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " st (\"123456789\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " et (\"\", 0)"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ct (\"string\", \"string_view\", 213, 33.12, \"c_style\", \"another_string\", 123)"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ct (\"string\", \"string_view\", 213, 33.12, \"c_style\", \"another_string\", 123) et (\"\", 0) st (\"123456789\")"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/UnorderedMap.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_unordered_map_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_unordered_map_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::unordered_map<int, double> idm = {{111, 3213.21}};
|
||||
LOG_INFO(logger, "idm {}", idm);
|
||||
|
||||
std::unordered_map<int, std::string> loopv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopv.emplace(iter, std::to_string(iter));
|
||||
}
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::unordered_map<std::string, std::string> loopsv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
|
||||
}
|
||||
LOG_INFO(logger, "loopsv {}", loopv);
|
||||
|
||||
std::unordered_map<char const*, char const*> ccm = {{"4", "400"}};
|
||||
LOG_INFO(logger, "ccm {}", ccm);
|
||||
|
||||
std::unordered_map<char const*, int> cim = {{"4", 4}};
|
||||
LOG_INFO(logger, "cim {}", cim);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccm {\"4\": \"400\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"4\": 4}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/UnorderedMap.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_unordered_multimap_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_unordered_multimap_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::unordered_multimap<int, double> idm = {{111, 3213.21}};
|
||||
LOG_INFO(logger, "idm {}", idm);
|
||||
|
||||
std::unordered_multimap<int, std::string> loopv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopv.emplace(iter, std::to_string(iter));
|
||||
}
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::unordered_multimap<std::string, std::string> loopsv;
|
||||
for (int iter = 0; iter < 25; ++iter)
|
||||
{
|
||||
loopsv.emplace(std::to_string(iter), std::to_string(iter * 2));
|
||||
}
|
||||
LOG_INFO(logger, "loopsv {}", loopv);
|
||||
|
||||
std::unordered_multimap<char const*, char const*> ccm = {{"4", "400"}};
|
||||
LOG_INFO(logger, "ccm {}", ccm);
|
||||
|
||||
std::unordered_multimap<char const*, int> cim = {{"4", 4}};
|
||||
LOG_INFO(logger, "cim {}", cim);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " idm {111: 3213.21}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccm {\"4\": \"400\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cim {\"4\": 4}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/UnorderedSet.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_unordered_multi_set_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_unordered_multi_set_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::unordered_multiset<char> c = {'a'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::unordered_multiset<short> si = {-12};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::unordered_multiset<int> i = {-123};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::unordered_multiset<long> li = {9876};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::unordered_multiset<long long> lli = {321};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::unordered_multiset<unsigned short> usi = {15};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::unordered_multiset<unsigned int> ui = {123};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::unordered_multiset<unsigned long> uli = {3213};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::unordered_multiset<unsigned long long> ulli = {321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::unordered_multiset<float> f = {111.1f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::unordered_multiset<double> d = {12.1};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::unordered_multiset<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::unordered_multiset<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::unordered_multiset<std::string> sa = {"test"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::unordered_multiset<std::string_view> sva = {"string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::unordered_multiset<char const*> scva = {"c_style"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
|
||||
|
||||
std::unordered_multiset<int> loopv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopv.insert(iter);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::unordered_multiset<std::string> loopsv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopsv.insert(std::to_string(iter));
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopsv {}", loopsv);
|
||||
|
||||
std::unordered_multiset<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a'}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li {9876}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli {321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi {15}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui {123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli {3213}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"} sa {\"test\"} ulli {321} scva {\"c_style\"} sa {\"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/UnorderedSet.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_unordered_set_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_unordered_set_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::unordered_set<char> c = {'a'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::unordered_set<short> si = {-12};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::unordered_set<int> i = {-123};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::unordered_set<long> li = {9876};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::unordered_set<long long> lli = {321};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::unordered_set<unsigned short> usi = {15};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::unordered_set<unsigned int> ui = {123};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::unordered_set<unsigned long> uli = {3213};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::unordered_set<unsigned long long> ulli = {321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::unordered_set<float> f = {111.1f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::unordered_set<double> d = {12.1};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::unordered_set<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::unordered_set<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::unordered_set<std::string> sa = {"test"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::unordered_set<std::string_view> sva = {"string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::unordered_set<char const*> scva = {"c_style"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {}", scva, sa, ulli, scva, sa);
|
||||
|
||||
std::unordered_set<int> loopv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopv.insert(iter);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::unordered_set<std::string> loopsv;
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopsv.insert(std::to_string(iter));
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopsv {}", loopsv);
|
||||
|
||||
std::unordered_set<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c {'a'}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si {-12}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i {-123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li {9876}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli {321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi {15}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui {123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli {3213}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli {321}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f {111.1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d {12.1}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri {-123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci {-123}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa {\"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva {\"string_view\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva {\"c_style\"} sa {\"test\"} ulli {321} scva {\"c_style\"} sa {\"test\"}"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv {"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt {}"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,255 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include "quill/std/Vector.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("std_vector_logging")
|
||||
{
|
||||
static constexpr char const* filename = "std_vector_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::vector<char> c = {'a', 'c'};
|
||||
LOG_INFO(logger, "c {}", c);
|
||||
|
||||
std::vector<short> si = {-12, 10};
|
||||
LOG_INFO(logger, "si {}", si);
|
||||
|
||||
std::vector<int> i = {-123, 1};
|
||||
LOG_INFO(logger, "i {}", i);
|
||||
|
||||
std::vector<long> li = {9876, 1232};
|
||||
LOG_INFO(logger, "li {}", li);
|
||||
|
||||
std::vector<long long> lli = {321, 231};
|
||||
LOG_INFO(logger, "lli {}", lli);
|
||||
|
||||
std::vector<unsigned short> usi = {15, 2};
|
||||
LOG_INFO(logger, "usi {}", usi);
|
||||
|
||||
std::vector<unsigned int> ui = {123, 2};
|
||||
LOG_INFO(logger, "ui {}", ui);
|
||||
|
||||
std::vector<unsigned long> uli = {3213, 2876};
|
||||
LOG_INFO(logger, "uli {}", uli);
|
||||
|
||||
std::vector<unsigned long long> ulli = {321, 1321};
|
||||
LOG_INFO(logger, "ulli {}", ulli);
|
||||
|
||||
std::vector<float> f = {111.1f, 323.31f};
|
||||
LOG_INFO(logger, "f {}", f);
|
||||
|
||||
std::vector<double> d = {12.1, 3213213.123};
|
||||
LOG_INFO(logger, "d {}", d);
|
||||
|
||||
std::vector<int> const& cri = i;
|
||||
LOG_INFO(logger, "cri {}", cri);
|
||||
|
||||
std::vector<int>& ci = i;
|
||||
LOG_INFO(logger, "ci {}", ci);
|
||||
|
||||
std::vector<std::string> sa = {"test", "string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::vector<std::string_view> sva = {"test", "string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::vector<char const*> scva = {"c style", "string test", "test", "log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::vector<std::vector<int>> aai = {{{321, 123}, {444, 333}, {111, 222}}};
|
||||
LOG_INFO(logger, "aai {}", aai);
|
||||
|
||||
std::vector<std::vector<char const*>> aacs = {
|
||||
{{"one", "two"}, {"three", "four"}, {"five", "six"}}};
|
||||
LOG_INFO(logger, "aacs {}", aacs);
|
||||
|
||||
std::vector<std::vector<std::vector<char const*>>> aaacs = {
|
||||
{{{{"one", "two"}, {"three", "four"}}},
|
||||
{{{"five", "six"}, {"seven", "eight"}}},
|
||||
{{{"nine", "ten"}, {"eleven", "twelve"}}}}};
|
||||
LOG_INFO(logger, "aaacs {}", aaacs);
|
||||
|
||||
{
|
||||
std::vector<std::vector<std::vector<std::string>>> aaabcs;
|
||||
|
||||
// First outer vector
|
||||
std::vector<std::vector<std::string>> first_outer = {{"std_one", "two"}, {"three", "four"}};
|
||||
|
||||
// Second outer vector
|
||||
std::vector<std::vector<std::string>> second_outer = {{"five", "six"}, {"seven", "eight"}};
|
||||
|
||||
// Third outer vector
|
||||
std::vector<std::vector<std::string>> third_outer = {{"std_nine", "ten"},
|
||||
{"eleven", "twelve"}};
|
||||
|
||||
aaabcs.push_back(first_outer);
|
||||
aaabcs.push_back(second_outer);
|
||||
aaabcs.push_back(third_outer);
|
||||
|
||||
LOG_INFO(logger, "aaabcs {}", aaabcs);
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<std::vector<std::vector<std::string>>> aaaccs;
|
||||
|
||||
// First outer vector
|
||||
std::vector<std::vector<std::string>> first_outer = {{"std_one", "two"},
|
||||
{"three_std", "four"}};
|
||||
|
||||
// Second outer vector
|
||||
std::vector<std::vector<std::string>> second_outer = {{"five", "six"}, {"seven_std", "eight"}};
|
||||
|
||||
// Third outer vector
|
||||
std::vector<std::vector<std::string>> third_outer = {{"std_nine", "ten"},
|
||||
{"eleven", "twelve"}};
|
||||
|
||||
aaaccs.push_back(first_outer);
|
||||
aaaccs.push_back(second_outer);
|
||||
aaaccs.push_back(third_outer);
|
||||
|
||||
LOG_INFO(logger, "aaaccs {}", aaaccs);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "scva {} sa {} ulli {} scva {} sa {} aaacs {} aai {}", scva, sa, ulli, scva, sa, aaacs, aai);
|
||||
|
||||
std::vector<int> loopv;
|
||||
loopv.reserve(100);
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopv.push_back(iter);
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopv {}", loopv);
|
||||
|
||||
std::vector<std::string> loopsv;
|
||||
loopsv.reserve(100);
|
||||
for (int iter = 0; iter < 100; ++iter)
|
||||
{
|
||||
loopsv.push_back(std::to_string(iter));
|
||||
}
|
||||
|
||||
LOG_INFO(logger, "loopsv {}", loopsv);
|
||||
|
||||
std::vector<int> empt;
|
||||
LOG_INFO(logger, "empt {}", empt);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c ['a', 'c']"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " si [-12, 10]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " i [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " li [9876, 1232]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " lli [321, 231]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usi [15, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ui [123, 2]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uli [3213, 2876]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ulli [321, 1321]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " f [111.1, 323.31]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " d [12.1, 3213213.123]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " cri [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ci [-123, 1]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aai [[321, 123], [444, 333], [111, 222]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" aacs [[\"one\", \"two\"], [\"three\", \"four\"], [\"five\", \"six\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaabcs [[[\"std_one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaaccs [[[\"std_one\", \"two\"], [\"three_std\", \"four\"]], [[\"five\", \"six\"], [\"seven_std\", \"eight\"]], [[\"std_nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] ulli [321, 1321] scva [\"c style\", \"string test\", \"test\", \"log\"] sa [\"test\", \"string\"] aaacs [[[\"one\", \"two\"], [\"three\", \"four\"]], [[\"five\", \"six\"], [\"seven\", \"eight\"]], [[\"nine\", \"ten\"], [\"eleven\", \"twelve\"]]] aai [[321, 123], [444, 333], [111, 222]]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopv [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " loopsv [\"0\", \"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", \"8\", \"9\", \"10\", \"11\", \"12\", \"13\", \"14\", \"15\", \"16\", \"17\", \"18\", \"19\", \"20\", \"21\", \"22\", \"23\", \"24\", \"25\", \"26\", \"27\", \"28\", \"29\", \"30\", \"31\", \"32\", \"33\", \"34\", \"35\", \"36\", \"37\", \"38\", \"39\", \"40\", \"41\", \"42\", \"43\", \"44\", \"45\", \"46\", \"47\", \"48\", \"49\", \"50\", \"51\", \"52\", \"53\", \"54\", \"55\", \"56\", \"57\", \"58\", \"59\", \"60\", \"61\", \"62\", \"63\", \"64\", \"65\", \"66\", \"67\", \"68\", \"69\", \"70\", \"71\", \"72\", \"73\", \"74\", \"75\", \"76\", \"77\", \"78\", \"79\", \"80\", \"81\", \"82\", \"83\", \"84\", \"85\", \"86\", \"87\", \"88\", \"89\", \"90\", \"91\", \"92\", \"93\", \"94\", \"95\", \"96\", \"97\", \"98\", \"99\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empt []"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_large_logging")
|
||||
{
|
||||
static constexpr char const* filename = "string_large_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_messages = 100;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string v{
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor "
|
||||
"incididunt ut labore et dolore magna aliqua. Dui accumsan sit amet nulla facilisi "
|
||||
"morbi tempus. Diam ut venenatis tellus in metus vulputate eu scelerisque felis. Lorem "
|
||||
"mollis aliquam ut porttitor leo a. Posuere urna nec tincidunt praesent semper feugiat "
|
||||
"nibh sed. Auctor urna nunc id cursus metus aliquam eleifend mi. Et ultrices neque ornare "
|
||||
"aenean euismod elementum nisi quis. Phasellus vestibulum lorem sed risus ultricies "
|
||||
"tristique nulla. Porta nibh venenatis cras sed felis eget velit aliquet sagittis. "
|
||||
"Eget arcu dictum varius duis at consectetur lorem. Diam quam nulla porttitor massa id "
|
||||
"neque aliquam vestibulum morbi. Sed euismod nisi porta lorem mollis aliquam. Arcu "
|
||||
"felis bibendum ut tristique. Lorem ipsum dolor sit amet consectetur adipiscing elit "
|
||||
"pellentesque habitant. Mauris augue neque gravida in. Dictum fusce ut placerat orci "
|
||||
"nulla pellentesque dignissim "};
|
||||
|
||||
v += std::to_string(i);
|
||||
|
||||
LOG_INFO(logger, "Logging int: {}, int: {}, string: {}, string: {}", i, i * 10, v, v);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_logging_dynamic_log_level")
|
||||
{
|
||||
static constexpr char const* filename = "string_logging_dynamic_log_level.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_messages = 10000;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
logger->set_log_level(LogLevel::TraceL3);
|
||||
|
||||
{
|
||||
std::string s = "adipiscing";
|
||||
std::string const empty_s{};
|
||||
|
||||
std::string_view begin_s{"begin_s"};
|
||||
std::string_view const end_s{"end_s"};
|
||||
std::string_view empty_sv{};
|
||||
|
||||
char const* c_style_string_empty = "";
|
||||
const char* c_style_string = "Lorem ipsum";
|
||||
|
||||
char c_style_char_array_empty[] = "";
|
||||
char const c_style_char_array[] = "dolor";
|
||||
|
||||
char c_style_string_array_non_terminated[3];
|
||||
c_style_string_array_non_terminated[0] = 'A';
|
||||
c_style_string_array_non_terminated[1] = 'B';
|
||||
c_style_string_array_non_terminated[2] = 'C';
|
||||
|
||||
LOG_DYNAMIC(logger, LogLevel::TraceL3, "s [{}]", s);
|
||||
LOG_DYNAMIC(logger, LogLevel::TraceL2, "empty_s [{}]", empty_s);
|
||||
LOG_DYNAMIC(logger, LogLevel::TraceL1, "begin_s [{}]", begin_s);
|
||||
LOG_DYNAMIC(logger, LogLevel::Debug, "end_s [{}]", end_s);
|
||||
LOG_DYNAMIC(logger, LogLevel::Info, "empty_sv [{}]", empty_sv);
|
||||
LOG_DYNAMIC(logger, LogLevel::Warning, "c_style_string_empty [{}]", c_style_string_empty);
|
||||
LOG_DYNAMIC(logger, LogLevel::Error, "c_style_string [{}]", c_style_string);
|
||||
LOG_DYNAMIC(logger, LogLevel::Critical, "c_style_char_array_empty [{}]", c_style_char_array_empty);
|
||||
LOG_DYNAMIC(logger, LogLevel::Info, "c_style_char_array [{}]", c_style_char_array);
|
||||
LOG_DYNAMIC(logger, LogLevel::Info, "c_style_string_array_non_terminated [{}]",
|
||||
c_style_string_array_non_terminated);
|
||||
|
||||
LOG_DYNAMIC(
|
||||
logger, LogLevel::Info,
|
||||
"Lorem ipsum dolor sit amet, consectetur [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
|
||||
s, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
|
||||
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated, s, "elit",
|
||||
1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
|
||||
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated);
|
||||
|
||||
LOG_DYNAMIC(logger, LogLevel::Error,
|
||||
"Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}]",
|
||||
2, true, begin_s, empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
|
||||
c_style_string, end_s, c_style_char_array_empty, c_style_char_array, 2, true,
|
||||
begin_s, empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
|
||||
c_style_string, end_s, c_style_char_array_empty, c_style_char_array);
|
||||
}
|
||||
|
||||
// Log a big string
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string v{"Lorem ipsum dolor sit amet, consectetur "};
|
||||
v += std::to_string(i);
|
||||
|
||||
LOG_DYNAMIC(logger, LogLevel::Info, "Logging int: {}, int: {}, string: {}, char: {}", i, i * 10,
|
||||
v, v.c_str());
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages + 12);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_TRACE_L3 " + logger_name + " s [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_TRACE_L2 " + logger_name + " empty_s []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_TRACE_L1 " + logger_name + " begin_s [begin_s]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_DEBUG " + logger_name + " end_s [end_s]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empty_sv []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_WARNING " + logger_name + " c_style_string_empty []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_ERROR " + logger_name + " c_style_string [Lorem ipsum]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_CRITICAL " + logger_name + " c_style_char_array_empty []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_char_array [dolor]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_array_non_terminated [ABC]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC] [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_ERROR " + logger_name + " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor] [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor]"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 0, int: 0, string: Lorem ipsum dolor sit amet, consectetur 0, char: Lorem ipsum dolor sit amet, consectetur 0"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 1999, int: 19990, string: Lorem ipsum dolor sit amet, consectetur 1999, char: Lorem ipsum dolor sit amet, consectetur 1999"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_logging")
|
||||
{
|
||||
static constexpr char const* filename = "string_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_messages = 10000;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::string s = "adipiscing";
|
||||
std::string const& scr = s;
|
||||
std::string& sr = s;
|
||||
std::string const empty_s{};
|
||||
|
||||
std::string_view begin_s{"begin_s"};
|
||||
std::string_view const end_s{"end_s"};
|
||||
std::string_view empty_sv{};
|
||||
|
||||
char const* c_style_string_empty = "";
|
||||
const char* c_style_string = "Lorem ipsum";
|
||||
|
||||
char c_style_char_array_empty[] = "";
|
||||
char const c_style_char_array[] = "dolor";
|
||||
|
||||
char c_style_string_array_non_terminated[3];
|
||||
c_style_string_array_non_terminated[0] = 'A';
|
||||
c_style_string_array_non_terminated[1] = 'B';
|
||||
c_style_string_array_non_terminated[2] = 'C';
|
||||
|
||||
LOG_INFO(logger, "s [{}]", s);
|
||||
LOG_INFO(logger, "scr [{}]", scr);
|
||||
LOG_INFO(logger, "sr [{}]", sr);
|
||||
LOG_INFO(logger, "empty_s [{}]", empty_s);
|
||||
LOG_INFO(logger, "begin_s [{}]", begin_s);
|
||||
LOG_INFO(logger, "end_s [{}]", end_s);
|
||||
LOG_INFO(logger, "empty_sv [{}]", empty_sv);
|
||||
LOG_INFO(logger, "c_style_string_empty [{}]", c_style_string_empty);
|
||||
LOG_INFO(logger, "c_style_string [{}]", c_style_string);
|
||||
LOG_INFO(logger, "c_style_char_array_empty [{}]", c_style_char_array_empty);
|
||||
LOG_INFO(logger, "c_style_char_array [{}]", c_style_char_array);
|
||||
LOG_INFO(logger, "c_style_string_array_non_terminated [{}]", c_style_string_array_non_terminated);
|
||||
|
||||
LOG_INFO(logger,
|
||||
"Lorem ipsum dolor sit amet, consectetur [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
|
||||
s, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
|
||||
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated, s,
|
||||
"elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty, c_style_string,
|
||||
c_style_char_array_empty, c_style_char_array, c_style_string_array_non_terminated);
|
||||
|
||||
LOG_ERROR(logger,
|
||||
"Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}]",
|
||||
2, true, begin_s, empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
|
||||
c_style_string, end_s, c_style_char_array_empty, c_style_char_array, 2, true, begin_s,
|
||||
empty_sv, empty_s, c_style_string_array_non_terminated, c_style_string_empty,
|
||||
c_style_string, end_s, c_style_char_array_empty, c_style_char_array);
|
||||
}
|
||||
|
||||
// Log a big string
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string v{"Lorem ipsum dolor sit amet, consectetur "};
|
||||
v += std::to_string(i);
|
||||
|
||||
LOG_INFO(logger, "Logging int: {}, int: {}, string: {}, char: {}", i, i * 10, v, v.c_str());
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages + 14);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " s [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scr [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sr [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empty_s []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " begin_s [begin_s]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " end_s [end_s]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empty_sv []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_empty []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string [Lorem ipsum]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_char_array_empty []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_char_array [dolor]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_array_non_terminated [ABC]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC] [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [] [dolor] [ABC]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_ERROR " + logger_name + " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor] [2] [true] [begin_s] [] [] [ABC] [] [Lorem ipsum] [end_s] [] [dolor]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 0, int: 0, string: Lorem ipsum dolor sit amet, consectetur 0, char: Lorem ipsum dolor sit amet, consectetur 0"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 1999, int: 19990, string: Lorem ipsum dolor sit amet, consectetur 1999, char: Lorem ipsum dolor sit amet, consectetur 1999"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_random_large_logging")
|
||||
{
|
||||
static constexpr char const* filename = "string_random_large_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_strings = 500;
|
||||
static constexpr int min_string_len = 10000;
|
||||
static constexpr int max_string_len = 20000;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
std::vector<std::string> random_strings_vec =
|
||||
quill::testing::gen_random_strings(number_of_strings, min_string_len, max_string_len);
|
||||
|
||||
// First push in sequence
|
||||
int32_t i = 0;
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
|
||||
++i;
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
|
||||
++i;
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
|
||||
++i;
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
|
||||
++i;
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
// Then also try to push all
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
LOG_INFO(logger, "{} {}", i, static_cast<double>(i));
|
||||
++i;
|
||||
}
|
||||
|
||||
// clear the vector for the strings to go out of scope for additional testing
|
||||
size_t const total_log_messages = random_strings_vec.size() * 14;
|
||||
random_strings_vec.clear();
|
||||
|
||||
// Let all log get flushed to the file
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check we logged everything
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), total_log_messages);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_random_logging")
|
||||
{
|
||||
static constexpr char const* filename = "string_random_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_strings = 2000;
|
||||
static constexpr int min_string_len = 1;
|
||||
static constexpr int max_string_len = 1500;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
std::vector<std::string> random_strings_vec =
|
||||
quill::testing::gen_random_strings(number_of_strings, min_string_len, max_string_len);
|
||||
|
||||
// First push in sequence
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
// Then also try to push all
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
}
|
||||
|
||||
// clear the vector for the strings to go out of scope for additional testing
|
||||
size_t const total_log_messages = random_strings_vec.size() * 9;
|
||||
random_strings_vec.clear();
|
||||
|
||||
// Let all log get flushed to the file
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check we logged everything
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), total_log_messages);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_random_small_logging")
|
||||
{
|
||||
static constexpr char const* filename = "string_random_small_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_strings = 500;
|
||||
static constexpr int min_string_len = 1;
|
||||
static constexpr int max_string_len = 50;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
std::vector<std::string> random_strings_vec =
|
||||
quill::testing::gen_random_strings(number_of_strings, min_string_len, max_string_len);
|
||||
|
||||
// First push in sequence
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
logger->flush_log();
|
||||
}
|
||||
|
||||
// Then also try to push all
|
||||
for (auto const& elem : random_strings_vec)
|
||||
{
|
||||
LOG_INFO(logger, "{}", elem);
|
||||
LOG_INFO(logger, "{}", elem.c_str());
|
||||
LOG_INFO(logger, "{}", std::string_view{elem});
|
||||
}
|
||||
|
||||
// clear the vector for the strings to go out of scope for additional testing
|
||||
size_t const total_log_messages = random_strings_vec.size() * 9;
|
||||
random_strings_vec.clear();
|
||||
|
||||
// Let all log get flushed to the file
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check we logged everything
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), total_log_messages);
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/Utility.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
class TestTags : public quill::Tags
|
||||
{
|
||||
public:
|
||||
explicit constexpr TestTags(char const* tag_a) : _tag_a(tag_a) {}
|
||||
|
||||
void format(std::string& out) const override { out.append(fmtquill::format("{}", _tag_a)); }
|
||||
|
||||
private:
|
||||
char const* _tag_a;
|
||||
};
|
||||
|
||||
static constexpr TestTags tags_a{"TAG_A"};
|
||||
static constexpr TestTags tags_b{"TAG_B"};
|
||||
|
||||
static constexpr quill::utility::CombinedTags<TestTags, TestTags> tags_ab{tags_a, tags_b, " -- "};
|
||||
|
||||
/***/
|
||||
TEST_CASE("tags_logging")
|
||||
{
|
||||
static constexpr char const* filename = "tags_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(
|
||||
logger_name, std::move(file_sink),
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) "
|
||||
"%(logger:<12) [%(tags)] %(message)\"");
|
||||
|
||||
logger->set_log_level(quill::LogLevel::TraceL3);
|
||||
|
||||
LOG_TRACE_L3_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_TRACE_L2_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_TRACE_L1_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_DEBUG_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_INFO_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_WARNING_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_ERROR_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
LOG_CRITICAL_WITH_TAGS(logger, tags_ab, "Lorem ipsum dolor sit amet, consectetur {} {} {}", "elit", 1, 3.14);
|
||||
|
||||
LOG_ERROR_WITH_TAGS(
|
||||
logger, tags_ab, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante {} {}", 2, true);
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), 9);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_TRACE_L3 " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_TRACE_L2 " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_TRACE_L1 " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_DEBUG " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_WARNING " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_ERROR " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_CRITICAL " + logger_name +
|
||||
" [TAG_A -- TAG_B] Lorem ipsum dolor sit amet, consectetur elit 1 3.14"}));
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_ERROR " + logger_name + " [TAG_A -- TAG_B] Nulla tempus, libero at dignissim viverra, lectus libero finibus ante 2 true"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/**
|
||||
* Custom timestamp class
|
||||
*/
|
||||
class UserClockSourceTest : public UserClockSource
|
||||
{
|
||||
public:
|
||||
UserClockSourceTest() = default;
|
||||
|
||||
/**
|
||||
* Required by TimestampClock
|
||||
* @return current time now, in nanoseconds since epoch
|
||||
*/
|
||||
uint64_t now() const override { return _ts.load(); }
|
||||
|
||||
/**
|
||||
* set custom timestamp
|
||||
* @param time_since_epoch timestamp
|
||||
*/
|
||||
void set_timestamp(std::chrono::seconds time_since_epoch)
|
||||
{
|
||||
// always convert to nanos
|
||||
_ts.store(static_cast<uint64_t>(std::chrono::nanoseconds{time_since_epoch}.count()));
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* time since epoch - must always be in nanoseconds
|
||||
* This class needs to be thread-safe, unless only a single thread in the application calling LOG macros
|
||||
* **/
|
||||
std::atomic<uint64_t> _ts;
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("user_clock_source")
|
||||
{
|
||||
static constexpr size_t number_of_messages = 10;
|
||||
static constexpr char const* filename = "user_clock_source.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
UserClockSourceTest uct;
|
||||
uct.set_timestamp(std::chrono::seconds{1655007309});
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink),
|
||||
"%(time) %(log_level) %(logger:<16) %(message)", // format
|
||||
"%Y-%m-%d %H:%M:%S.%Qms", // timestamp format
|
||||
quill::Timezone::GmtTime, ClockSourceType::User, &uct);
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
// log an array so the log message is pushed to the queue
|
||||
LOG_INFO(logger, "Lorem ipsum dolor sit amet, consectetur adipiscing elit {}", i);
|
||||
}
|
||||
|
||||
uct.set_timestamp(std::chrono::seconds{1656007309});
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
LOG_ERROR(logger, "Nulla tempus, libero at dignissim viverra, lectus libero finibus ante {}", i);
|
||||
}
|
||||
|
||||
// Let all log get flushed to the file
|
||||
uct.set_timestamp(std::chrono::seconds{1658007309});
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages * 2);
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string expected_string = "2022-06-12 04:15:09.000 INFO " + logger_name +
|
||||
" Lorem ipsum dolor sit amet, consectetur adipiscing elit " + std::to_string(i);
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::string expected_string = "2022-06-23 18:01:49.000 ERROR " + logger_name +
|
||||
" Nulla tempus, libero at dignissim viverra, lectus libero finibus ante " +
|
||||
std::to_string(i);
|
||||
REQUIRE(quill::testing::file_contains(file_contents, expected_string));
|
||||
}
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/Utility.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include "quill/core/Codec.h"
|
||||
#include "quill/core/DynamicFormatArgStore.h"
|
||||
#include "quill/std/Array.h"
|
||||
#include "quill/std/Vector.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/**
|
||||
* CustomType defined type
|
||||
*/
|
||||
struct CustomType
|
||||
{
|
||||
std::string name;
|
||||
std::string surname;
|
||||
uint32_t age;
|
||||
std::array<std::string, 3> favorite_colors;
|
||||
};
|
||||
|
||||
/***/
|
||||
template <>
|
||||
struct fmtquill::formatter<CustomType>
|
||||
{
|
||||
template <typename FormatContext>
|
||||
constexpr auto parse(FormatContext& ctx)
|
||||
{
|
||||
return ctx.begin();
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
auto format(::CustomType const& custom_type, FormatContext& ctx) const
|
||||
{
|
||||
return fmtquill::format_to(ctx.out(), "Name: {}, Surname: {}, Age: {}, Favorite Colors: {}",
|
||||
custom_type.name, custom_type.surname, custom_type.age,
|
||||
custom_type.favorite_colors);
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
template <>
|
||||
struct quill::detail::ArgSizeCalculator<CustomType>
|
||||
{
|
||||
static size_t calculate(std::vector<size_t>& conditional_arg_size_cache, ::CustomType const& custom_type) noexcept
|
||||
{
|
||||
// pass as arguments the class members you want to serialize
|
||||
return calculate_total_size(conditional_arg_size_cache, custom_type.name, custom_type.surname,
|
||||
custom_type.age, custom_type.favorite_colors);
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
template <>
|
||||
struct quill::detail::Encoder<CustomType>
|
||||
{
|
||||
static void encode(std::byte*& buffer, std::vector<size_t> const& conditional_arg_size_cache,
|
||||
uint32_t& conditional_arg_size_cache_index, ::CustomType const& custom_type) noexcept
|
||||
{
|
||||
// You must encode the same members and in the same order as in the ArgSizeCalculator::calculate
|
||||
encode_members(buffer, conditional_arg_size_cache, conditional_arg_size_cache_index,
|
||||
custom_type.name, custom_type.surname, custom_type.age, custom_type.favorite_colors);
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
template <>
|
||||
struct quill::detail::Decoder<CustomType>
|
||||
{
|
||||
static ::CustomType decode(std::byte*& buffer, DynamicFormatArgStore* args_store)
|
||||
{
|
||||
// You must decode the same members and in the same order as in the Encoder::encode
|
||||
::CustomType custom_type;
|
||||
decode_and_assign_members(buffer, args_store, custom_type, custom_type.name,
|
||||
custom_type.surname, custom_type.age, custom_type.favorite_colors);
|
||||
return custom_type;
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("custom_type_defined_type_logging")
|
||||
{
|
||||
static constexpr char const* filename = "custom_type_defined_type_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(
|
||||
logger_name, std::move(file_sink),
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) LOG_%(log_level:<9) "
|
||||
"%(logger:<12) %(message)");
|
||||
|
||||
logger->set_log_level(quill::LogLevel::TraceL3);
|
||||
|
||||
CustomType custom_type;
|
||||
custom_type.name = "Quill";
|
||||
custom_type.surname = "Library";
|
||||
custom_type.age = 4;
|
||||
custom_type.favorite_colors[0] = "red";
|
||||
custom_type.favorite_colors[1] = "green";
|
||||
custom_type.favorite_colors[2] = "blue";
|
||||
|
||||
LOG_INFO(logger, "The answer is {}", custom_type);
|
||||
|
||||
std::vector<CustomType> const custom_types = {{"Alice", "Doe", 25, {"red", "green"}},
|
||||
{"Bob", "Smith", 30, {"blue", "yellow"}},
|
||||
{"Charlie", "Johnson", 35, {"green", "orange"}},
|
||||
{"David", "Brown", 40, {"red", "blue", "yellow"}}};
|
||||
|
||||
LOG_INFO(logger, "The answers are {}", custom_types);
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), 2);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " The answer is Name: Quill, Surname: Library, Age: 4, Favorite Colors: [\"red\", \"green\", \"blue\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " The answers are [Name: Alice, Surname: Doe, Age: 25, Favorite Colors: [\"red\", \"green\", \"\"], Name: Bob, Surname: Smith, Age: 30, Favorite Colors: [\"blue\", \"yellow\", \"\"], Name: Charlie, Surname: Johnson, Age: 35, Favorite Colors: [\"green\", \"orange\", \"\"], Name: David, Surname: Brown, Age: 40, Favorite Colors: [\"red\", \"blue\", \"yellow\"]]"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
}
|
|
@ -0,0 +1,330 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/core/Filesystem.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include "quill/std/Array.h"
|
||||
#include "quill/std/Deque.h"
|
||||
#include "quill/std/FilesystemPath.h"
|
||||
#include "quill/std/ForwardList.h"
|
||||
#include "quill/std/List.h"
|
||||
#include "quill/std/Map.h"
|
||||
#include "quill/std/Optional.h"
|
||||
#include "quill/std/Pair.h"
|
||||
#include "quill/std/Set.h"
|
||||
#include "quill/std/UnorderedMap.h"
|
||||
#include "quill/std/UnorderedSet.h"
|
||||
#include "quill/std/Vector.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstdio>
|
||||
#include <deque>
|
||||
#include <forward_list>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
struct CWideStringComparator
|
||||
{
|
||||
bool operator()(wchar_t const* a, wchar_t const* b) const { return std::wcscmp(a, b) < 0; }
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("wide_std_types_logging")
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static constexpr char const* filename = "wide_std_types_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
fs::path wp{L"C:\\some\\path"};
|
||||
LOG_INFO(logger, "wp {}", wp);
|
||||
|
||||
fs::path p{"C:\\another\\path"};
|
||||
LOG_INFO(logger, "p {}", p);
|
||||
|
||||
LOG_INFO(logger, "wp {} p {}", wp, p);
|
||||
|
||||
std::array<std::wstring, 2> wsa = {L"test", L"string"};
|
||||
LOG_INFO(logger, "wsa {}", wsa);
|
||||
|
||||
std::array<std::wstring_view, 2> wsva = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "wsva {}", wsva);
|
||||
|
||||
std::array<wchar_t const*, 4> wscva = {L"c style", L"string test", L"test", L"log"};
|
||||
LOG_INFO(logger, "wscva {}", wscva);
|
||||
|
||||
std::deque<std::wstring> wds = {L"test", L"string"};
|
||||
LOG_INFO(logger, "wds {}", wds);
|
||||
|
||||
std::deque<std::wstring_view> wdsv = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "wdsv {}", wdsv);
|
||||
|
||||
std::deque<wchar_t const*> wdcs = {L"c style", L"string test", L"test", L"log"};
|
||||
LOG_INFO(logger, "wdcs {}", wdcs);
|
||||
|
||||
std::forward_list<std::wstring> wfs = {L"test", L"string"};
|
||||
LOG_INFO(logger, "wfs {}", wfs);
|
||||
|
||||
std::forward_list<std::wstring_view> wfsv = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "wfsv {}", wfsv);
|
||||
|
||||
std::forward_list<wchar_t const*> wfcs = {L"c style", L"string test", L"test", L"log"};
|
||||
LOG_INFO(logger, "wfcs {}", wfcs);
|
||||
|
||||
std::list<std::wstring> sl = {L"test", L"string"};
|
||||
LOG_INFO(logger, "sl {}", sl);
|
||||
|
||||
std::list<std::wstring_view> svl = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "svl {}", svl);
|
||||
|
||||
std::list<wchar_t const*> scl = {L"c style", L"string test", L"test", L"log"};
|
||||
LOG_INFO(logger, "scl {}", scl);
|
||||
|
||||
std::vector<std::wstring> wsv = {L"test", L"string"};
|
||||
LOG_INFO(logger, "wsv {}", wsv);
|
||||
|
||||
std::vector<std::wstring_view> wsvv = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "wsvv {}", wsvv);
|
||||
|
||||
std::vector<wchar_t const*> wscv = {L"c style", L"string test", L"test", L"log"};
|
||||
LOG_INFO(logger, "wscv {}", wscv);
|
||||
|
||||
std::pair<std::wstring, std::wstring> wpss = {L"test", L"string"};
|
||||
LOG_INFO(logger, "wpss {}", wpss);
|
||||
|
||||
std::pair<std::wstring_view, std::wstring> wpsv = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "wpsv {}", wpsv);
|
||||
|
||||
std::pair<wchar_t const*, std::wstring> wscs = {L"c style", L"string test"};
|
||||
LOG_INFO(logger, "wscs {}", wscs);
|
||||
|
||||
std::pair<int, std::wstring> wscsi = {1231, L"string test"};
|
||||
LOG_INFO(logger, "wscsi {}", wscsi);
|
||||
|
||||
std::pair<std::wstring, double> wscsd = {L"string test", 443.2};
|
||||
LOG_INFO(logger, "wscsd {}", wscsd);
|
||||
|
||||
std::optional<std::wstring> weo{std::nullopt};
|
||||
LOG_INFO(logger, "eo {}", weo);
|
||||
|
||||
std::optional<std::wstring> wos{L"test"};
|
||||
LOG_INFO(logger, "wos {}", wos);
|
||||
|
||||
std::optional<std::wstring_view> wosv{L"test"};
|
||||
LOG_INFO(logger, "wosv {}", wosv);
|
||||
|
||||
std::optional<wchar_t const*> woc{L"test"};
|
||||
LOG_INFO(logger, "woc {}", woc);
|
||||
|
||||
std::set<std::wstring> sa = {L"test", L"string"};
|
||||
LOG_INFO(logger, "sa {}", sa);
|
||||
|
||||
std::set<std::wstring> sva = {L"test", L"string_view"};
|
||||
LOG_INFO(logger, "sva {}", sva);
|
||||
|
||||
std::set<wchar_t const*, CWideStringComparator> scva = {L"c_style", L"aa", L"string_test",
|
||||
L"test", L"log"};
|
||||
LOG_INFO(logger, "scva {}", scva);
|
||||
|
||||
std::map<std::wstring, std::wstring> ccm = {{L"4", L"400"}, {L"3", L"300"}, {L"1", L"100"}};
|
||||
LOG_INFO(logger, "ccm {}", ccm);
|
||||
|
||||
std::map<std::wstring, int> ccmx = {{L"4", 400}, {L"3", 300}, {L"1", 100}};
|
||||
LOG_INFO(logger, "ccmx {}", ccmx);
|
||||
|
||||
std::map<wchar_t const*, std::wstring, CWideStringComparator> ccmc = {
|
||||
{L"4", L"400"}, {L"3", L"300"}, {L"1", L"100"}};
|
||||
LOG_INFO(logger, "ccmc {}", ccmc);
|
||||
|
||||
std::map<int, std::wstring> ccmi = {{4, L"400"}, {3, L"300"}, {1, L"100"}};
|
||||
LOG_INFO(logger, "ccmi {}", ccmi);
|
||||
|
||||
std::unordered_set<std::wstring> uss = {L"test"};
|
||||
LOG_INFO(logger, "uss {}", uss);
|
||||
|
||||
std::unordered_set<std::wstring_view> usvs = {L"string_view"};
|
||||
LOG_INFO(logger, "usvs {}", usvs);
|
||||
|
||||
std::unordered_set<wchar_t const*> uscs = {L"c_style"};
|
||||
LOG_INFO(logger, "uscs {}", uscs);
|
||||
|
||||
std::unordered_map<std::wstring, std::wstring> uccm = {{L"4", L"400"}};
|
||||
LOG_INFO(logger, "uccm {}", uccm);
|
||||
|
||||
std::unordered_map<std::wstring, int> uccmx = {{L"5", 500}};
|
||||
LOG_INFO(logger, "uccmx {}", uccmx);
|
||||
|
||||
std::unordered_map<wchar_t const*, std::wstring> uccmc = {{L"6", L"600"}};
|
||||
LOG_INFO(logger, "uccmc {}", uccmc);
|
||||
|
||||
std::unordered_map<int, std::wstring> uccmi = {{7, L"700"}};
|
||||
LOG_INFO(logger, "uccmi {}", uccmi);
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wp C:\\some\\path"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " p C:\\another\\path"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wp C:\\some\\path p C:\\another\\path"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wsa [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wsva [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wscva [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wds [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wdsv [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wdcs [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wfs [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wfsv [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wfcs [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sl [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " svl [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " scl [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wsv [\"test\", \"string\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wsvv [\"test\", \"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wscv [\"c style\", \"string test\", \"test\", \"log\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wpss (\"test\", \"string\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wpsv (\"test\", \"string_view\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wscs (\"c style\", \"string test\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wscsi (1231, \"string test\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wscsd (\"string test\", 443.2)"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " eo none"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wos optional(\"test\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " wosv optional(\"test\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " woc optional(\"test\")"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sa [\"string\", \"test\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " sva [\"string_view\", \"test\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents,
|
||||
std::string{"LOG_INFO " + logger_name +
|
||||
" scva [\"aa\", \"c_style\", \"log\", \"string_test\", \"test\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccm [(\"1\", \"100\"), (\"3\", \"300\"), (\"4\", \"400\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccmx [(\"1\", 100), (\"3\", 300), (\"4\", 400)]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccmc [(\"1\", \"100\"), (\"3\", \"300\"), (\"4\", \"400\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ccmi [(1, \"100\"), (3, \"300\"), (4, \"400\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uss [\"test\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " usvs [\"string_view\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uscs [\"c_style\"]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uccm [(\"4\", \"400\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uccmx [(\"5\", 500)]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uccmc [(\"6\", \"600\")]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " uccmi [(7, \"700\")]"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
#endif
|
||||
}
|
|
@ -0,0 +1,136 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/Backend.h"
|
||||
#include "quill/Frontend.h"
|
||||
#include "quill/LogMacros.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
using namespace quill;
|
||||
|
||||
/***/
|
||||
TEST_CASE("wide_string_logging")
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
static constexpr char const* filename = "wide_string_logging.log";
|
||||
static std::string const logger_name = "logger";
|
||||
static constexpr size_t number_of_messages = 10000;
|
||||
|
||||
// Start the logging backend thread
|
||||
Backend::start();
|
||||
|
||||
Frontend::preallocate();
|
||||
|
||||
// Set writing logging to a file
|
||||
auto file_sink = Frontend::create_or_get_sink<FileSink>(
|
||||
filename,
|
||||
[]()
|
||||
{
|
||||
FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
Logger* logger = Frontend::create_or_get_logger(logger_name, std::move(file_sink));
|
||||
|
||||
{
|
||||
std::string s = "adipiscing";
|
||||
std::wstring ws = L"adipiscing";
|
||||
std::wstring const empty_s{};
|
||||
|
||||
std::wstring_view begin_s{L"begin_s"};
|
||||
std::wstring_view const end_s{L"end_s"};
|
||||
std::wstring_view empty_sv{};
|
||||
|
||||
wchar_t const* c_style_string_empty = L"";
|
||||
wchar_t const* c_style_string = L"Lorem ipsum";
|
||||
|
||||
LOG_INFO(logger, "s [{}]", s);
|
||||
LOG_INFO(logger, "ws [{}]", ws);
|
||||
LOG_INFO(logger, "empty_s [{}]", empty_s);
|
||||
LOG_INFO(logger, "begin_s [{}]", begin_s);
|
||||
LOG_INFO(logger, "end_s [{}]", end_s);
|
||||
LOG_INFO(logger, "empty_sv [{}]", empty_sv);
|
||||
LOG_INFO(logger, "c_style_string_empty [{}]", c_style_string_empty);
|
||||
LOG_INFO(logger, "c_style_string [{}]", c_style_string);
|
||||
|
||||
LOG_INFO(logger,
|
||||
"Lorem ipsum dolor sit amet, consectetur [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
|
||||
ws, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv, c_style_string_empty,
|
||||
c_style_string, ws, "elit", 1, 3.14, empty_s, begin_s, end_s, empty_sv,
|
||||
c_style_string_empty, c_style_string, s);
|
||||
|
||||
LOG_ERROR(logger,
|
||||
"Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [{}] [{}] "
|
||||
"[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}]",
|
||||
2, true, begin_s, empty_sv, empty_s, c_style_string_empty, c_style_string, end_s, 2,
|
||||
true, begin_s, empty_sv, empty_s, c_style_string_empty, c_style_string, end_s, s);
|
||||
}
|
||||
|
||||
// Log a big string
|
||||
for (size_t i = 0; i < number_of_messages; ++i)
|
||||
{
|
||||
std::wstring v{
|
||||
L"Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem "
|
||||
L"ipsum dolor sit amet, consectetur "};
|
||||
v += std::to_wstring(i);
|
||||
|
||||
LOG_INFO(logger, "Logging int: {}, int: {}, string: {}, char: {}", i, i * 10, v, v.c_str());
|
||||
}
|
||||
|
||||
logger->flush_log();
|
||||
Frontend::remove_logger(logger);
|
||||
|
||||
// Wait until the backend thread stops for test stability
|
||||
Backend::stop();
|
||||
|
||||
// Read file and check
|
||||
std::vector<std::string> const file_contents = quill::testing::file_contents(filename);
|
||||
REQUIRE_EQ(file_contents.size(), number_of_messages + 10);
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " s [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " ws [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empty_s []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " begin_s [begin_s]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " end_s [end_s]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " empty_sv []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string_empty []"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " c_style_string [Lorem ipsum]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Lorem ipsum dolor sit amet, consectetur [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [adipiscing] [elit] [1] [3.14] [] [begin_s] [end_s] [] [] [Lorem ipsum] [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_ERROR " + logger_name + " Nulla tempus, libero at dignissim viverra, lectus libero finibus ante [2] [true] [begin_s] [] [] [] [Lorem ipsum] [end_s] [2] [true] [begin_s] [] [] [] [Lorem ipsum] [end_s] [adipiscing]"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 0, int: 0, string: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 0, char: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 0"}));
|
||||
|
||||
REQUIRE(quill::testing::file_contains(
|
||||
file_contents, std::string{"LOG_INFO " + logger_name + " Logging int: 1999, int: 19990, string: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 1999, char: Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur 1999"}));
|
||||
|
||||
testing::remove_file(filename);
|
||||
#endif
|
||||
}
|
190
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.cpp
Normal file
190
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include "DocTestExtensions.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if !defined(NOMINMAX)
|
||||
// Mingw already defines this, so no need to redefine
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <codecvt>
|
||||
#include <io.h>
|
||||
#include <locale>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
|
||||
// The ctor redirects the stream to a temporary file.
|
||||
CapturedStream::CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd))
|
||||
{
|
||||
#if defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(_WIN32)
|
||||
char temp_dir_path[MAX_PATH + 1] = {'\0'}; // NOLINT
|
||||
char temp_file_path[MAX_PATH + 1] = {'\0'}; // NOLINT
|
||||
|
||||
::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
|
||||
const UINT success = ::GetTempFileNameA(temp_dir_path, "dtest_redir",
|
||||
0, // Generate unique file name.
|
||||
temp_file_path);
|
||||
if (success == 0)
|
||||
{
|
||||
FAIL("Unable to create a temporary file in " << temp_dir_path;);
|
||||
}
|
||||
|
||||
const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
|
||||
if (captured_fd == -1)
|
||||
{
|
||||
FAIL("Unable to open_file temporary file " << temp_file_path);
|
||||
}
|
||||
filename_ = temp_file_path;
|
||||
#else
|
||||
// There's no guarantee that a test has write access to the current
|
||||
// directory, so we create the temporary file in the /tmp directory
|
||||
// instead.
|
||||
// We use /tmp on most systems, and /sdcard on Android.
|
||||
// That's because Android doesn't have /tmp.
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
char name_template[] = "/data/local/tmp/doctest_captured_stream.XXXXXX";
|
||||
#else
|
||||
char name_template[] = "/tmp/captured_stream.XXXXXX";
|
||||
#endif // __ANDROID__
|
||||
|
||||
const int captured_fd = mkstemp(name_template);
|
||||
|
||||
if (captured_fd == -1)
|
||||
{
|
||||
FAIL("Failed to create tmp file "
|
||||
<< name_template << " for test; does the test have access to the /tmp directory?");
|
||||
}
|
||||
|
||||
filename_ = name_template;
|
||||
#endif // _WIN32
|
||||
|
||||
fflush(nullptr);
|
||||
dup2(captured_fd, fd_);
|
||||
close(captured_fd);
|
||||
}
|
||||
|
||||
CapturedStream::~CapturedStream() { remove(filename_.c_str()); }
|
||||
|
||||
std::string CapturedStream::GetCapturedString()
|
||||
{
|
||||
if (uncaptured_fd_ != -1)
|
||||
{
|
||||
// Restores the original stream.
|
||||
fflush(nullptr);
|
||||
dup2(uncaptured_fd_, fd_);
|
||||
close(uncaptured_fd_);
|
||||
uncaptured_fd_ = -1;
|
||||
}
|
||||
|
||||
FILE* const file = _fopen(filename_.c_str(), "r");
|
||||
if (file == nullptr)
|
||||
{
|
||||
// FAIL("Failed to open_file tmp file " << filename_ << " for capturing stream.");
|
||||
}
|
||||
|
||||
std::string content = _read_entire_file(file);
|
||||
_fclose(file);
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string CapturedStream::_read_entire_file(FILE* file)
|
||||
{
|
||||
size_t const file_size = _get_file_size(file);
|
||||
std::unique_ptr<char[]> buffer{new char[file_size]};
|
||||
|
||||
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
||||
size_t bytes_read = 0; // # of bytes read so far
|
||||
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
do
|
||||
{
|
||||
// Keeps reading the file until we cannot read further or the
|
||||
// pre-determined file size is reached.
|
||||
bytes_last_read = fread(buffer.get() + bytes_read, 1, file_size - bytes_read, file);
|
||||
bytes_read += bytes_last_read;
|
||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||
|
||||
std::string content{buffer.get(), bytes_read};
|
||||
return content;
|
||||
}
|
||||
|
||||
size_t CapturedStream::_get_file_size(FILE* file)
|
||||
{
|
||||
fseek(file, 0, SEEK_END);
|
||||
return static_cast<size_t>(ftell(file));
|
||||
}
|
||||
|
||||
FILE* CapturedStream::_fopen(char const* path, char const* mode)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
struct wchar_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t>
|
||||
{
|
||||
};
|
||||
std::wstring_convert<wchar_codecvt> converter;
|
||||
std::wstring wide_path = converter.from_bytes(path);
|
||||
std::wstring wide_mode = converter.from_bytes(mode);
|
||||
return _wfopen(wide_path.c_str(), wide_mode.c_str());
|
||||
#else
|
||||
return fopen(path, mode);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
int CapturedStream::_fclose(FILE* fp) { return fclose(fp); }
|
||||
|
||||
// Starts capturing an output stream (stdout/stderr).
|
||||
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream)
|
||||
{
|
||||
if (*stream != nullptr)
|
||||
{
|
||||
FAIL("Only one " << stream_name << " capturer can exist at a time.");
|
||||
}
|
||||
*stream = new CapturedStream(fd);
|
||||
}
|
||||
|
||||
// Stops capturing the output stream and returns the captured string.
|
||||
std::string GetCapturedStream(CapturedStream** captured_stream)
|
||||
{
|
||||
std::string content = (*captured_stream)->GetCapturedString();
|
||||
|
||||
delete *captured_stream;
|
||||
*captured_stream = nullptr;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
|
||||
const int kStdOutFileno = 1;
|
||||
const int kStdErrFileno = 2;
|
||||
#else
|
||||
const int kStdOutFileno = STDOUT_FILENO;
|
||||
const int kStdErrFileno = STDERR_FILENO;
|
||||
#endif // _MSC_VER
|
||||
|
||||
void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); }
|
||||
|
||||
void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); }
|
||||
|
||||
std::string GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
|
||||
|
||||
std::string GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
|
||||
|
||||
} // namespace testing
|
||||
} // namespace quill
|
97
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.h
Normal file
97
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
|
||||
#include "doctest/doctest.h"
|
||||
#include "quill/core/Attributes.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#define REQUIRE_STREQ(str1, str2) \
|
||||
do \
|
||||
{ \
|
||||
if (strcmp(str1, str2) != 0) \
|
||||
{ \
|
||||
MESSAGE("Expected equality of these values: \n\t str1: " \
|
||||
<< std::string_view{str1} << "\n\t str2: " << std::string_view{str2}); \
|
||||
REQUIRE_UNARY(false); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_WSTREQ(str1, str2) \
|
||||
do \
|
||||
{ \
|
||||
if (wcscmp(str1, str2) != 0) \
|
||||
{ \
|
||||
MESSAGE("Expected equality of these values: \n\t str1: " << str1 << "\n\t str2: " << str2); \
|
||||
REQUIRE_UNARY(false); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_STRNEQ(str1, str2) \
|
||||
do \
|
||||
{ \
|
||||
if (strcmp(str1, str2) == 0) \
|
||||
{ \
|
||||
MESSAGE("Expected non-equality of these values: \n\t str1: " << str1 << "\n\t str2: " << str2); \
|
||||
REQUIRE_UNARY(false); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
/**
|
||||
* Object that captures an output stream (stdout/stderr).
|
||||
*/
|
||||
class CapturedStream
|
||||
{
|
||||
public:
|
||||
// The ctor redirects the stream to a temporary file.
|
||||
explicit CapturedStream(int fd);
|
||||
|
||||
~CapturedStream();
|
||||
|
||||
std::string GetCapturedString();
|
||||
|
||||
private:
|
||||
static std::string _read_entire_file(FILE* file);
|
||||
|
||||
static size_t _get_file_size(FILE* file);
|
||||
|
||||
static FILE* _fopen(char const* path, char const* mode);
|
||||
|
||||
static int _fclose(FILE* fp);
|
||||
|
||||
private:
|
||||
int fd_; // A stream to capture.
|
||||
int uncaptured_fd_;
|
||||
std::string filename_; // Name of the temporary file holding the stderr output.
|
||||
};
|
||||
|
||||
QUILL_MAYBE_UNUSED static CapturedStream* g_captured_stderr = nullptr;
|
||||
QUILL_MAYBE_UNUSED static CapturedStream* g_captured_stdout = nullptr;
|
||||
|
||||
// Starts capturing an output stream (stdout/stderr).
|
||||
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream);
|
||||
|
||||
// Stops capturing the output stream and returns the captured string.
|
||||
std::string GetCapturedStream(CapturedStream** captured_stream);
|
||||
|
||||
// Starts capturing stdout.
|
||||
void CaptureStdout();
|
||||
|
||||
// Starts capturing stderr.
|
||||
void CaptureStderr();
|
||||
|
||||
// Stops capturing stdout and returns the captured string.
|
||||
std::string GetCapturedStdout();
|
||||
|
||||
// Stops capturing stderr and returns the captured string.
|
||||
std::string GetCapturedStderr();
|
||||
} // namespace testing
|
||||
} // namespace quill
|
2
subprojects/quill-4.2.0/quill/test/misc/TestMain.cpp
Normal file
2
subprojects/quill-4.2.0/quill/test/misc/TestMain.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "doctest/doctest.h"
|
155
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.cpp
Normal file
155
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include "TestUtilities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
// Convert the given file to a vector
|
||||
std::vector<std::string> file_contents(fs::path const& filename)
|
||||
{
|
||||
std::ifstream out_file(filename.string());
|
||||
|
||||
std::vector<std::string> lines;
|
||||
|
||||
for (std::string current_line; getline(out_file, current_line);)
|
||||
{
|
||||
lines.push_back(current_line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
// Convert the given file to a vector
|
||||
std::vector<std::wstring> wfile_contents(fs::path const& filename)
|
||||
{
|
||||
std::wifstream out_file(filename.string());
|
||||
|
||||
std::vector<std::wstring> lines;
|
||||
|
||||
for (std::wstring current_line; getline(out_file, current_line);)
|
||||
{
|
||||
lines.push_back(current_line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
// Search a vector for the given string
|
||||
bool file_contains(std::vector<std::string> const& file_vector, std::string const& search_string)
|
||||
{
|
||||
auto const search =
|
||||
std::find_if(file_vector.cbegin(), file_vector.cend(), [&search_string](std::string const& elem)
|
||||
{ return elem.find(search_string) != std::string::npos; });
|
||||
|
||||
bool const success = search != file_vector.cend();
|
||||
|
||||
if (!success)
|
||||
{
|
||||
// We failed to find and we will log for diagnostic reasons
|
||||
std::cout << "Failed to find '" << search_string << "' in:\n";
|
||||
for (auto const& line : file_vector)
|
||||
{
|
||||
std::cout << "'" << line << "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void create_file(fs::path const& filename, std::string const& text)
|
||||
{
|
||||
if (std::ofstream file(filename); file.is_open())
|
||||
{
|
||||
if (!text.empty())
|
||||
{
|
||||
file << text;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void remove_file(fs::path const& filename)
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::remove(filename, ec);
|
||||
}
|
||||
|
||||
std::vector<std::string> gen_random_strings(size_t n, int min_len, int max_len)
|
||||
{
|
||||
// Generate random strings
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
std::uniform_int_distribution<int> dist_chars(32, 126);
|
||||
|
||||
// length of strings
|
||||
std::uniform_int_distribution<int> dist_len(min_len, max_len);
|
||||
|
||||
// Generate a vector of random strings of dist_len
|
||||
std::vector<std::string> random_strings_vec;
|
||||
random_strings_vec.reserve(n);
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
std::generate_n(std::back_inserter(result), dist_len(mt),
|
||||
[&] { return static_cast<char>(dist_chars(mt)); });
|
||||
random_strings_vec.emplace_back(std::move(result));
|
||||
}
|
||||
return random_strings_vec;
|
||||
}
|
||||
|
||||
uint64_t parse_timestamp(std::string const& timestamp_str)
|
||||
{
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(timestamp_str);
|
||||
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S"); // Extract date and time
|
||||
|
||||
// Extract fractional seconds
|
||||
size_t pos = timestamp_str.find('.');
|
||||
std::string fractional_seconds_str = timestamp_str.substr(pos + 1, 9);
|
||||
uint64_t fractional_seconds = std::stoull(fractional_seconds_str);
|
||||
|
||||
auto time_point = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||
auto nanoseconds_since_epoch =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(time_point.time_since_epoch()).count();
|
||||
return static_cast<uint64_t>(nanoseconds_since_epoch) + fractional_seconds;
|
||||
}
|
||||
|
||||
bool is_timestamp_ordered(std::vector<std::string> const& file_contents)
|
||||
{
|
||||
uint64_t previous_timestamp = 0;
|
||||
bool first = true;
|
||||
|
||||
for (auto const& line : file_contents)
|
||||
{
|
||||
uint64_t current_timestamp = parse_timestamp(line);
|
||||
|
||||
if (!first)
|
||||
{
|
||||
if (current_timestamp < previous_timestamp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
previous_timestamp = current_timestamp;
|
||||
first = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace testing
|
||||
} // namespace quill
|
30
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.h
Normal file
30
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "quill/core/Common.h"
|
||||
#include "quill/core/Filesystem.h"
|
||||
|
||||
#include "DocTestExtensions.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
// Convert the given file to a vector
|
||||
std::vector<std::string> file_contents(fs::path const& filename);
|
||||
std::vector<std::wstring> wfile_contents(fs::path const& filename);
|
||||
|
||||
// Search a vector for the given string
|
||||
bool file_contains(std::vector<std::string> const& file_vector, std::string const& search_string);
|
||||
void create_file(fs::path const& filename, std::string const& text = std::string{});
|
||||
void remove_file(fs::path const& filename);
|
||||
|
||||
std::vector<std::string> gen_random_strings(size_t n, int min_len, int max_len);
|
||||
|
||||
uint64_t parse_timestamp(std::string const& timestamp_str);
|
||||
bool is_timestamp_ordered(std::vector<std::string> const& file_contents);
|
||||
} // namespace testing
|
||||
} // namespace quill
|
|
@ -0,0 +1,137 @@
|
|||
#include "doctest/doctest.h"
|
||||
#include "misc/DocTestExtensions.h"
|
||||
|
||||
#include "quill/core/BoundedSPSCQueue.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
TEST_SUITE_BEGIN("BoundedQueue");
|
||||
|
||||
using namespace quill::detail;
|
||||
|
||||
#if !defined(QUILL_X86ARCH)
|
||||
// QUILL_X86ARCH requires at least a queue capacity of 1024 and those tests are using a smaller number
|
||||
|
||||
TEST_CASE("read_write_buffer")
|
||||
{
|
||||
BoundedSPSCQueue buffer{64u};
|
||||
|
||||
for (uint32_t i = 0; i < 128; ++i)
|
||||
{
|
||||
{
|
||||
std::byte* write_buf = buffer.prepare_write(32u);
|
||||
REQUIRE_NE(write_buf, nullptr);
|
||||
buffer.finish_write(32u);
|
||||
buffer.commit_write();
|
||||
}
|
||||
|
||||
{
|
||||
std::byte* write_buf = buffer.prepare_write(32u);
|
||||
REQUIRE_NE(write_buf, nullptr);
|
||||
buffer.finish_write(32u);
|
||||
buffer.commit_write();
|
||||
}
|
||||
|
||||
{
|
||||
std::byte* res = buffer.prepare_read();
|
||||
REQUIRE(res);
|
||||
buffer.finish_read(32u);
|
||||
buffer.commit_read();
|
||||
}
|
||||
|
||||
{
|
||||
std::byte* res = buffer.prepare_read();
|
||||
REQUIRE(res);
|
||||
buffer.finish_read(32u);
|
||||
buffer.commit_read();
|
||||
|
||||
res = buffer.prepare_read();
|
||||
REQUIRE_FALSE(res);
|
||||
}
|
||||
}
|
||||
|
||||
std::byte* res = buffer.prepare_read();
|
||||
REQUIRE_FALSE(res);
|
||||
}
|
||||
|
||||
TEST_CASE("bounded_queue_integer_overflow")
|
||||
{
|
||||
BoundedSPSCQueueImpl<uint8_t> buffer{128, false, 0};
|
||||
size_t constexpr iterations = static_cast<size_t>(std::numeric_limits<uint8_t>::max()) * 8ull;
|
||||
|
||||
for (size_t i = 0; i < iterations; ++i)
|
||||
{
|
||||
std::string to_write{"test"};
|
||||
to_write += std::to_string(i);
|
||||
std::byte* r = buffer.prepare_write(static_cast<uint8_t>(to_write.length()) + 1);
|
||||
std::strncpy(reinterpret_cast<char*>(r), to_write.data(), to_write.length() + 1);
|
||||
buffer.finish_write(static_cast<uint8_t>(to_write.length()) + 1);
|
||||
buffer.commit_write();
|
||||
|
||||
// now read
|
||||
std::byte* w = buffer.prepare_read();
|
||||
REQUIRE(w);
|
||||
char result[256];
|
||||
std::memcpy(&result[0], w, static_cast<uint8_t>(to_write.length()) + 1);
|
||||
REQUIRE_STREQ(result, to_write.data());
|
||||
buffer.finish_read(static_cast<uint8_t>(to_write.length()) + 1);
|
||||
buffer.commit_read();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("bounded_queue_read_write_multithreaded_plain_ints")
|
||||
{
|
||||
BoundedSPSCQueue buffer{131'072};
|
||||
|
||||
std::thread producer_thread(
|
||||
[&buffer]()
|
||||
{
|
||||
for (uint32_t wrap_cnt = 0; wrap_cnt < 20; ++wrap_cnt)
|
||||
{
|
||||
for (uint32_t i = 0; i < 8192; ++i)
|
||||
{
|
||||
std::byte* write_buffer = buffer.prepare_write(sizeof(uint32_t));
|
||||
|
||||
while (!write_buffer)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{2});
|
||||
write_buffer = buffer.prepare_write(sizeof(uint32_t));
|
||||
}
|
||||
|
||||
std::memcpy(write_buffer, &i, sizeof(uint32_t));
|
||||
buffer.finish_write(sizeof(uint32_t));
|
||||
buffer.commit_write();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
std::thread consumer_thread(
|
||||
[&buffer]()
|
||||
{
|
||||
for (uint32_t wrap_cnt = 0; wrap_cnt < 20; ++wrap_cnt)
|
||||
{
|
||||
for (uint32_t i = 0; i < 8192; ++i)
|
||||
{
|
||||
std::byte const* read_buffer = buffer.prepare_read();
|
||||
while (!read_buffer)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{2});
|
||||
read_buffer = buffer.prepare_read();
|
||||
}
|
||||
|
||||
auto const value = reinterpret_cast<uint32_t const*>(read_buffer);
|
||||
REQUIRE_EQ(*value, i);
|
||||
buffer.finish_read(sizeof(uint32_t));
|
||||
buffer.commit_read();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
producer_thread.join();
|
||||
consumer_thread.join();
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
66
subprojects/quill-4.2.0/quill/test/unit_tests/CMakeLists.txt
Normal file
66
subprojects/quill-4.2.0/quill/test/unit_tests/CMakeLists.txt
Normal file
|
@ -0,0 +1,66 @@
|
|||
function(quill_add_test TEST_NAME SOURCES)
|
||||
set(HEADER_FILES
|
||||
${PROJECT_SOURCE_DIR}/quill/test/bundled/doctest/doctest.h
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/TestUtilities.h
|
||||
)
|
||||
|
||||
set(ADD_SOURCE_FILES
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/TestMain.cpp
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/TestUtilities.cpp
|
||||
${PROJECT_SOURCE_DIR}/quill/test/misc/DocTestExtensions.cpp)
|
||||
|
||||
list(APPEND SOURCES ${ADD_SOURCE_FILES})
|
||||
|
||||
# Create a test executable
|
||||
add_executable(${TEST_NAME} "")
|
||||
|
||||
set_common_compile_options(${TEST_NAME})
|
||||
|
||||
# Add sources
|
||||
target_sources(${TEST_NAME} PRIVATE ${SOURCES} ${HEADER_FILES})
|
||||
|
||||
# include dirs
|
||||
target_include_directories(${TEST_NAME}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/quill/test/misc>
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/quill/test/bundled>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/quill/test)
|
||||
|
||||
# Link dependencies
|
||||
target_link_libraries(${TEST_NAME} quill)
|
||||
|
||||
# Do not decay cxx standard if not specified
|
||||
set_property(TARGET ${TEST_NAME} PROPERTY CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Set output test directory
|
||||
set_target_properties(${TEST_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/build/test)
|
||||
|
||||
# Add this target to the post build unit tests
|
||||
doctest_discover_tests(${TEST_NAME})
|
||||
endfunction()
|
||||
|
||||
include(${PROJECT_SOURCE_DIR}/cmake/doctest.cmake)
|
||||
|
||||
quill_add_test(TEST_BoundedQueueTest BoundedQueueTest.cpp)
|
||||
quill_add_test(TEST_DynamicFormatArgStore DynamicFormatArgStoreTest.cpp)
|
||||
quill_add_test(TEST_FileUtilities FileUtilitiesTest.cpp)
|
||||
quill_add_test(TEST_LoggerManager LoggerManagerTest.cpp)
|
||||
quill_add_test(TEST_Logger LoggerTest.cpp)
|
||||
quill_add_test(TEST_LogLevel LogLevelTest.cpp)
|
||||
quill_add_test(TEST_MacroMetadata MacroMetadataTest.cpp)
|
||||
quill_add_test(TEST_MathUtils MathUtilsTest.cpp)
|
||||
quill_add_test(TEST_PatternFormatter PatternFormatterTest.cpp)
|
||||
quill_add_test(TEST_RotatingFileSink RotatingFileSinkTest.cpp)
|
||||
quill_add_test(TEST_SinkManager SinkManagerTest.cpp)
|
||||
quill_add_test(TEST_StringFromTime StringFromTimeTest.cpp)
|
||||
quill_add_test(TEST_ThreadContextManager ThreadContextManagerTest.cpp)
|
||||
quill_add_test(TEST_TimestampFormatter TimestampFormatterTest.cpp)
|
||||
quill_add_test(TEST_TransitEventBuffer TransitEventBufferTest.cpp)
|
||||
quill_add_test(TEST_UnboundedQueue.cpp UnboundedQueueTest.cpp)
|
||||
quill_add_test(TEST_Utility UtilityTest.cpp)
|
||||
|
||||
if (NOT QUILL_USE_VALGRIND)
|
||||
quill_add_test(TEST_RdtscClock RdtscClockTest.cpp)
|
||||
endif ()
|
|
@ -0,0 +1,33 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/DocTestExtensions.h"
|
||||
#include "quill/core/DynamicFormatArgStore.h"
|
||||
|
||||
#include "quill/bundled/fmt/format.h"
|
||||
|
||||
TEST_SUITE_BEGIN("DynamicFormatArgStore");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("dynamic_format_arg_store")
|
||||
{
|
||||
// DynamicFormatArgStore store;
|
||||
DynamicFormatArgStore store;
|
||||
|
||||
store.push_back(42);
|
||||
store.push_back(std::string_view{"abc"});
|
||||
store.push_back(1.5f);
|
||||
|
||||
// c style string allocates
|
||||
store.push_back("efg");
|
||||
|
||||
std::string result = fmtquill::vformat(
|
||||
"{} and {} and {} and {}",
|
||||
fmtquill::basic_format_args<fmtquill::format_context>{store.get_types(), store.data()});
|
||||
|
||||
REQUIRE_EQ(result, std::string{"42 and abc and 1.5 and efg"});
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,166 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/DocTestExtensions.h"
|
||||
#include "quill/core/Common.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
|
||||
TEST_SUITE_BEGIN("FileUtilities");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
class FileSinkMock : public quill::FileSink
|
||||
{
|
||||
public:
|
||||
static std::pair<std::string, std::string> extract_stem_and_extension(
|
||||
fs::path const& filename) noexcept
|
||||
{
|
||||
return quill::FileSink::extract_stem_and_extension(filename);
|
||||
}
|
||||
|
||||
static fs::path append_datetime_to_filename(
|
||||
fs::path const& filename, bool with_time = false, Timezone timezone = Timezone::LocalTime,
|
||||
std::chrono::system_clock::time_point timestamp = {}) noexcept
|
||||
{
|
||||
return quill::FileSink::append_datetime_to_filename(filename, with_time, timezone, timestamp);
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("extract_stem_and_extension")
|
||||
{
|
||||
{
|
||||
// simple file
|
||||
fs::path fname = "logfile";
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), fname.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), "");
|
||||
}
|
||||
|
||||
{
|
||||
// simple directory
|
||||
fs::path fname = "etc";
|
||||
fname /= "eng";
|
||||
fname /= "logfile";
|
||||
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), fname.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), "");
|
||||
}
|
||||
|
||||
{
|
||||
// no file extension
|
||||
fs::path fname = "logfile.";
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), "logfile");
|
||||
REQUIRE_STREQ(res.second.data(), ".");
|
||||
}
|
||||
|
||||
{
|
||||
// no file extension - directory
|
||||
fs::path fname = "etc";
|
||||
fname /= "eng";
|
||||
fname /= "logfile.";
|
||||
|
||||
fs::path fname_expected = "etc";
|
||||
fname_expected /= "eng";
|
||||
fname_expected /= "logfile";
|
||||
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), fname_expected.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), ".");
|
||||
}
|
||||
|
||||
{
|
||||
// hidden file
|
||||
fs::path fname = ".logfile.";
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), ".logfile");
|
||||
REQUIRE_STREQ(res.second.data(), ".");
|
||||
}
|
||||
|
||||
#ifndef QUILL_HAS_EXPERIMENTAL_FILESYSTEM
|
||||
{
|
||||
// hidden file - directory
|
||||
fs::path fname = "etc";
|
||||
fname /= "eng";
|
||||
fname /= ".logfile";
|
||||
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
|
||||
// in gcc 7.3.1 with experimental filesystem this line fails with str1: etc/eng != str2: /etc/eng/.logfile
|
||||
REQUIRE_STREQ(res.first.data(), fname.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), "");
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
// valid stem and extension
|
||||
fs::path fname = "logfile.log";
|
||||
fs::path fname_expected = "logfile";
|
||||
fs::path extension_expected = ".log";
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), fname_expected.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), extension_expected.string().data());
|
||||
}
|
||||
|
||||
{
|
||||
// valid stem and extension - directory
|
||||
fs::path fname = "etc";
|
||||
fname /= "eng";
|
||||
fname /= "logfile.log";
|
||||
|
||||
fs::path fname_expected = "etc";
|
||||
fname_expected /= "eng";
|
||||
fname_expected /= "logfile";
|
||||
|
||||
fs::path extension_expected = ".log";
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), fname_expected.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), extension_expected.string().data());
|
||||
}
|
||||
|
||||
{
|
||||
// valid stem and extension - directory
|
||||
fs::path fname = "/etc";
|
||||
fname /= "eng";
|
||||
fname /= "logfile.log";
|
||||
|
||||
fs::path fname_expected = "/etc";
|
||||
fname_expected /= "eng";
|
||||
fname_expected /= "logfile";
|
||||
|
||||
fs::path extension_expected = ".log";
|
||||
auto const res = FileSinkMock::extract_stem_and_extension(fname);
|
||||
REQUIRE_STREQ(res.first.data(), fname_expected.string().data());
|
||||
REQUIRE_STREQ(res.second.data(), extension_expected.string().data());
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("append_date_to_filename")
|
||||
{
|
||||
std::chrono::system_clock::time_point const ts =
|
||||
std::chrono::system_clock::time_point{std::chrono::seconds{1583376945}};
|
||||
fs::path const expected_fname = "logfile_20200305.log";
|
||||
fs::path const base_fname = "logfile.log";
|
||||
|
||||
REQUIRE_STREQ(
|
||||
FileSinkMock::append_datetime_to_filename(base_fname, false, quill::Timezone::GmtTime, ts).string().data(),
|
||||
expected_fname.string().data());
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("append_datetime_to_filename")
|
||||
{
|
||||
std::chrono::system_clock::time_point const ts =
|
||||
std::chrono::system_clock::time_point{std::chrono::seconds{1583376945}};
|
||||
fs::path const expected_fname = "logfile_20200305_025545.log";
|
||||
fs::path const base_fname = "logfile.log";
|
||||
|
||||
REQUIRE_STREQ(
|
||||
FileSinkMock::append_datetime_to_filename(base_fname, true, quill::Timezone::GmtTime, ts).string().data(),
|
||||
expected_fname.string().data());
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
146
subprojects/quill-4.2.0/quill/test/unit_tests/LogLevelTest.cpp
Normal file
146
subprojects/quill-4.2.0/quill/test/unit_tests/LogLevelTest.cpp
Normal file
|
@ -0,0 +1,146 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/core/LogLevel.h"
|
||||
#include "quill/core/QuillError.h"
|
||||
|
||||
TEST_SUITE_BEGIN("LogLevel");
|
||||
|
||||
using namespace quill;
|
||||
using namespace std::literals;
|
||||
|
||||
/***/
|
||||
TEST_CASE("loglevel_to_string")
|
||||
{
|
||||
{
|
||||
LogLevel log_level{LogLevel::Dynamic};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "DYNAMIC");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::None};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "NONE");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::Backtrace};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "BACKTRACE");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::Critical};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "CRITICAL");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::Error};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "ERROR");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::Warning};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "WARNING");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::Info};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "INFO");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::Debug};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "DEBUG");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::TraceL1};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "TRACE_L1");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::TraceL2};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "TRACE_L2");
|
||||
}
|
||||
|
||||
{
|
||||
LogLevel log_level{LogLevel::TraceL3};
|
||||
REQUIRE_STREQ(loglevel_to_string(log_level).data(), "TRACE_L3");
|
||||
}
|
||||
|
||||
{
|
||||
#ifndef QUILL_NO_EXCEPTIONS
|
||||
LogLevel log_level;
|
||||
log_level = static_cast<LogLevel>(-1);
|
||||
REQUIRE_THROWS_AS(QUILL_MAYBE_UNUSED auto s = loglevel_to_string(log_level).data(), quill::QuillError);
|
||||
REQUIRE_THROWS_AS(QUILL_MAYBE_UNUSED auto s = loglevel_to_string_id(log_level).data(), quill::QuillError);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("loglevel_from_string")
|
||||
{
|
||||
{
|
||||
std::string log_level{"Dynamic"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Dynamic);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"None"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::None);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"Backtrace"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Backtrace);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"Critical"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Critical);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"Error"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Error);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"Warning"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Warning);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"Info"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Info);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"Debug"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::Debug);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"TraceL1"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::TraceL1);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"TraceL2"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::TraceL2);
|
||||
}
|
||||
|
||||
{
|
||||
std::string log_level{"TraceL3"};
|
||||
REQUIRE_EQ(loglevel_from_string(log_level), LogLevel::TraceL3);
|
||||
}
|
||||
|
||||
{
|
||||
#ifndef QUILL_NO_EXCEPTIONS
|
||||
std::string log_level{"dummy"};
|
||||
REQUIRE_THROWS_AS(QUILL_MAYBE_UNUSED auto res = loglevel_from_string(log_level), quill::QuillError);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,125 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
#include "quill/core/LoggerManager.h"
|
||||
#include "quill/sinks/ConsoleSink.h"
|
||||
|
||||
TEST_SUITE_BEGIN("LoggerManager");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("create_get_remove_logger")
|
||||
{
|
||||
std::shared_ptr<ConsoleSink> sink = std::make_unique<ConsoleSink>();
|
||||
|
||||
LoggerManager& lm = LoggerManager::instance();
|
||||
|
||||
std::vector<std::shared_ptr<Sink>> sinks;
|
||||
sinks.push_back(sink);
|
||||
|
||||
LoggerBase* logger_1 = lm.create_or_get_logger<Logger>(
|
||||
"logger_1", std::move(sinks),
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) "
|
||||
"LOG_%(log_level:<9) %(logger:<12) %(message)",
|
||||
"%H:%M:%S.%Qns", quill::Timezone::GmtTime, ClockSourceType::Tsc, nullptr);
|
||||
|
||||
LoggerBase* logger_2 = lm.create_or_get_logger<Logger>(
|
||||
"logger_2", std::initializer_list<std::shared_ptr<Sink>>{sink},
|
||||
"[%(thread_id)] %(short_source_location:<28) "
|
||||
"LOG_%(log_level:<9) %(logger:<12) %(message)",
|
||||
"%H:%M:%S.%Qns", quill::Timezone::GmtTime, ClockSourceType::Tsc, nullptr);
|
||||
|
||||
REQUIRE_EQ(logger_1->get_logger_name(), "logger_1");
|
||||
REQUIRE_EQ(logger_2->get_logger_name(), "logger_2");
|
||||
|
||||
REQUIRE_EQ(lm.get_logger("logger_1")->get_logger_name(), "logger_1");
|
||||
REQUIRE_EQ(lm.get_logger("logger_2")->get_logger_name(), "logger_2");
|
||||
REQUIRE_EQ(lm.get_logger("logger_3"), nullptr);
|
||||
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 2);
|
||||
REQUIRE_EQ(lm.get_all_loggers()[0]->get_logger_name(), "logger_1");
|
||||
REQUIRE_EQ(lm.get_all_loggers()[1]->get_logger_name(), "logger_2");
|
||||
|
||||
// try_remove_logger_1_queue_has_pending_messages
|
||||
{
|
||||
lm.remove_logger(logger_1);
|
||||
|
||||
// Logger is only marked invalid at this stage
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 1);
|
||||
REQUIRE_EQ(lm.get_all_loggers()[0]->get_logger_name(), "logger_2");
|
||||
|
||||
// count will include also the invalidated loggers
|
||||
REQUIRE_EQ(lm.get_number_of_loggers(), 2);
|
||||
|
||||
// Logger is not removed yet because we have pending records
|
||||
std::vector<std::string> const removed_loggers =
|
||||
lm.cleanup_invalidated_loggers([]() { return false; });
|
||||
|
||||
REQUIRE_EQ(removed_loggers.size(), 0);
|
||||
REQUIRE_EQ(lm.get_number_of_loggers(), 2);
|
||||
}
|
||||
|
||||
// try_remove_logger_1_queue_is_empty
|
||||
{
|
||||
lm.remove_logger(logger_1);
|
||||
|
||||
// Logger is only marked invalid at this stage
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 1);
|
||||
REQUIRE_EQ(lm.get_all_loggers()[0]->get_logger_name(), "logger_2");
|
||||
|
||||
// count will include also the invalidated loggers
|
||||
REQUIRE_EQ(lm.get_number_of_loggers(), 2);
|
||||
|
||||
// Logger is removed since we pass true meaning the queue is empty
|
||||
std::vector<std::string> const removed_loggers =
|
||||
lm.cleanup_invalidated_loggers([]() { return true; });
|
||||
|
||||
REQUIRE_EQ(removed_loggers.size(), 1);
|
||||
REQUIRE_EQ(removed_loggers[0], "logger_1");
|
||||
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 1);
|
||||
REQUIRE_EQ(lm.get_all_loggers()[0]->get_logger_name(), "logger_2");
|
||||
|
||||
// Number of loggers is also updated after removal
|
||||
REQUIRE_EQ(lm.get_number_of_loggers(), 1);
|
||||
}
|
||||
|
||||
// try_remove_logger_2_queue_has_pending_messages
|
||||
{
|
||||
lm.remove_logger(logger_2);
|
||||
|
||||
// Logger is only marked invalid at this stage
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 0);
|
||||
|
||||
// Logger is not removed yet because we have pending records
|
||||
std::vector<std::string> const removed_loggers =
|
||||
lm.cleanup_invalidated_loggers([]() { return false; });
|
||||
|
||||
REQUIRE_EQ(removed_loggers.size(), 0);
|
||||
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 0);
|
||||
REQUIRE_EQ(lm.get_number_of_loggers(), 1);
|
||||
}
|
||||
|
||||
// try_remove_logger_2_queue_is_empty
|
||||
{
|
||||
lm.remove_logger(logger_2);
|
||||
|
||||
// Logger is only marked invalid at this stage
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 0);
|
||||
|
||||
// Logger is removed since we pass true meaning the queue is empty
|
||||
std::vector<std::string> const removed_loggers =
|
||||
lm.cleanup_invalidated_loggers([]() { return true; });
|
||||
|
||||
REQUIRE_EQ(removed_loggers.size(), 1);
|
||||
REQUIRE_EQ(removed_loggers[0], "logger_2");
|
||||
|
||||
REQUIRE_EQ(lm.get_all_loggers().size(), 0);
|
||||
REQUIRE_EQ(lm.get_number_of_loggers(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
70
subprojects/quill-4.2.0/quill/test/unit_tests/LoggerTest.cpp
Normal file
70
subprojects/quill-4.2.0/quill/test/unit_tests/LoggerTest.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/Logger.h"
|
||||
#include "quill/core/LoggerManager.h"
|
||||
|
||||
#include "quill/sinks/ConsoleSink.h"
|
||||
|
||||
TEST_SUITE_BEGIN("Logger");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("check_logger")
|
||||
{
|
||||
std::shared_ptr<ConsoleSink> sink = std::make_unique<ConsoleSink>();
|
||||
|
||||
LoggerManager& lm = LoggerManager::instance();
|
||||
|
||||
std::vector<std::shared_ptr<Sink>> sinks;
|
||||
sinks.push_back(std::move(sink));
|
||||
|
||||
Logger* logger_1 = static_cast<Logger*>(lm.create_or_get_logger<Logger>(
|
||||
"logger_1", std::move(sinks),
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) "
|
||||
"LOG_%(log_level:<9) %(logger:<12) %(message)",
|
||||
"%H:%M:%S.%Qns", quill::Timezone::GmtTime, ClockSourceType::Tsc, nullptr));
|
||||
|
||||
// Check default log level
|
||||
REQUIRE_EQ(logger_1->get_log_level(), LogLevel::Info);
|
||||
REQUIRE_EQ(logger_1->get_logger_name(), "logger_1");
|
||||
|
||||
#ifndef QUILL_NO_EXCEPTIONS
|
||||
// throw if backtrace log level is used
|
||||
REQUIRE_THROWS_AS(logger_1->set_log_level(LogLevel::Backtrace), quill::QuillError);
|
||||
#endif
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("logger_should_log")
|
||||
{
|
||||
std::shared_ptr<ConsoleSink> sink = std::make_unique<ConsoleSink>();
|
||||
|
||||
LoggerManager& lm = LoggerManager::instance();
|
||||
|
||||
std::vector<std::shared_ptr<Sink>> sinks;
|
||||
sinks.push_back(std::move(sink));
|
||||
|
||||
Logger* logger_1 = static_cast<Logger*>(lm.create_or_get_logger<Logger>(
|
||||
"logger_1", std::move(sinks),
|
||||
"%(time) [%(thread_id)] %(short_source_location:<28) "
|
||||
"LOG_%(log_level:<9) %(logger:<12) %(message)",
|
||||
"%H:%M:%S.%Qns", quill::Timezone::GmtTime, ClockSourceType::Tsc, nullptr));
|
||||
|
||||
REQUIRE_UNARY_FALSE(logger_1->should_log_message<LogLevel::Debug>());
|
||||
REQUIRE(logger_1->should_log_message<LogLevel::Info>());
|
||||
REQUIRE(logger_1->should_log_message<LogLevel::Error>());
|
||||
|
||||
// change log level
|
||||
logger_1->set_log_level(LogLevel::TraceL3);
|
||||
REQUIRE(logger_1->should_log_message<LogLevel::TraceL3>());
|
||||
REQUIRE(logger_1->should_log_message<LogLevel::Critical>());
|
||||
|
||||
// change log level
|
||||
logger_1->set_log_level(LogLevel::None);
|
||||
REQUIRE_UNARY_FALSE(logger_1->should_log_message<LogLevel::TraceL3>());
|
||||
REQUIRE_UNARY_FALSE(logger_1->should_log_message<LogLevel::Critical>());
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,88 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/core/Common.h"
|
||||
#include "quill/core/MacroMetadata.h"
|
||||
|
||||
TEST_SUITE_BEGIN("MacroMetadata");
|
||||
|
||||
using namespace quill::detail;
|
||||
using namespace quill;
|
||||
|
||||
TEST_CASE("construct")
|
||||
{
|
||||
{
|
||||
constexpr MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__FUNCTION__,
|
||||
"Test fmt {}",
|
||||
nullptr,
|
||||
quill::LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
REQUIRE_STREQ(macro_metadata.message_format(), "Test fmt {}");
|
||||
REQUIRE_EQ(macro_metadata.log_level(), quill::LogLevel::Debug);
|
||||
REQUIRE_STREQ(macro_metadata.line(), "15");
|
||||
REQUIRE_EQ(macro_metadata.has_named_args(), false);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__FUNCTION__,
|
||||
"Test another fmt {name}",
|
||||
nullptr,
|
||||
quill::LogLevel::Info,
|
||||
MacroMetadata::Event::Flush};
|
||||
|
||||
REQUIRE_STREQ(macro_metadata.message_format(), "Test another fmt {name}");
|
||||
REQUIRE_EQ(macro_metadata.log_level(), quill::LogLevel::Info);
|
||||
REQUIRE_STREQ(macro_metadata.line(), "29");
|
||||
REQUIRE_EQ(macro_metadata.file_name(), std::string_view{"MacroMetadataTest.cpp"});
|
||||
REQUIRE_STREQ(macro_metadata.short_source_location(), "MacroMetadataTest.cpp:29");
|
||||
REQUIRE_STREQ(macro_metadata.caller_function(), "DOCTEST_ANON_FUNC_3");
|
||||
REQUIRE_EQ(macro_metadata.event(), MacroMetadata::Event::Flush);
|
||||
REQUIRE_EQ(macro_metadata.has_named_args(), true);
|
||||
REQUIRE_NE(std::string_view{macro_metadata.source_location()}.find("MacroMetadataTest.cpp"),
|
||||
std::string_view::npos);
|
||||
REQUIRE_NE(std::string_view{macro_metadata.full_path()}.find("MacroMetadataTest.cpp"),
|
||||
std::string_view::npos);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__FUNCTION__,
|
||||
"Test another fmt {name} and {surname} and {{age}}",
|
||||
nullptr,
|
||||
quill::LogLevel::Info,
|
||||
MacroMetadata::Event::Flush};
|
||||
|
||||
REQUIRE_STREQ(macro_metadata.message_format(),
|
||||
"Test another fmt {name} and {surname} and {{age}}");
|
||||
REQUIRE_EQ(macro_metadata.log_level(), quill::LogLevel::Info);
|
||||
REQUIRE_STREQ(macro_metadata.line(), "51");
|
||||
REQUIRE_EQ(macro_metadata.file_name(), std::string_view{"MacroMetadataTest.cpp"});
|
||||
REQUIRE_STREQ(macro_metadata.short_source_location(), "MacroMetadataTest.cpp:51");
|
||||
REQUIRE_STREQ(macro_metadata.caller_function(), "DOCTEST_ANON_FUNC_3");
|
||||
REQUIRE_EQ(macro_metadata.event(), MacroMetadata::Event::Flush);
|
||||
REQUIRE_EQ(macro_metadata.has_named_args(), true);
|
||||
}
|
||||
|
||||
{
|
||||
constexpr MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__FUNCTION__,
|
||||
"Test another fmt {0} and {1} and {2}",
|
||||
nullptr,
|
||||
quill::LogLevel::Info,
|
||||
MacroMetadata::Event::Flush};
|
||||
|
||||
REQUIRE_STREQ(macro_metadata.message_format(), "Test another fmt {0} and {1} and {2}");
|
||||
REQUIRE_EQ(macro_metadata.log_level(), quill::LogLevel::Info);
|
||||
REQUIRE_STREQ(macro_metadata.line(), "70");
|
||||
REQUIRE_EQ(macro_metadata.file_name(), std::string_view{"MacroMetadataTest.cpp"});
|
||||
REQUIRE_STREQ(macro_metadata.short_source_location(), "MacroMetadataTest.cpp:70");
|
||||
REQUIRE_STREQ(macro_metadata.caller_function(), "DOCTEST_ANON_FUNC_3");
|
||||
REQUIRE_EQ(macro_metadata.event(), MacroMetadata::Event::Flush);
|
||||
REQUIRE_EQ(macro_metadata.has_named_args(), false);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,81 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/TestUtilities.h"
|
||||
#include "quill/core/MathUtils.h"
|
||||
|
||||
TEST_SUITE_BEGIN("MathUtils");
|
||||
|
||||
using namespace quill::detail;
|
||||
using namespace quill;
|
||||
|
||||
TEST_CASE("is_power_of_two")
|
||||
{
|
||||
// Test with power of two numbers
|
||||
CHECK(is_power_of_two(1) == true);
|
||||
CHECK(is_power_of_two(2) == true);
|
||||
CHECK(is_power_of_two(4) == true);
|
||||
CHECK(is_power_of_two(8) == true);
|
||||
CHECK(is_power_of_two(16) == true);
|
||||
CHECK(is_power_of_two(1024) == true);
|
||||
|
||||
// Test with non-power of two numbers
|
||||
CHECK(is_power_of_two(0) == false);
|
||||
CHECK(is_power_of_two(3) == false);
|
||||
CHECK(is_power_of_two(5) == false);
|
||||
CHECK(is_power_of_two(6) == false);
|
||||
CHECK(is_power_of_two(7) == false);
|
||||
CHECK(is_power_of_two(9) == false);
|
||||
|
||||
// Test edge cases
|
||||
CHECK(is_power_of_two(std::numeric_limits<std::size_t>::max()) == false);
|
||||
}
|
||||
|
||||
TEST_CASE("next_power_of_two_unsigned")
|
||||
{
|
||||
// Test with numbers that are already powers of two
|
||||
CHECK(next_power_of_two(1u) == 1u);
|
||||
CHECK(next_power_of_two(2u) == 2u);
|
||||
CHECK(next_power_of_two(4u) == 4u);
|
||||
CHECK(next_power_of_two(8u) == 8u);
|
||||
CHECK(next_power_of_two(16u) == 16u);
|
||||
CHECK(next_power_of_two(1024u) == 1024u);
|
||||
|
||||
// Test with numbers that are not powers of two
|
||||
CHECK(next_power_of_two(0u) == 1u);
|
||||
CHECK(next_power_of_two(3u) == 4u);
|
||||
CHECK(next_power_of_two(5u) == 8u);
|
||||
CHECK(next_power_of_two(6u) == 8u);
|
||||
CHECK(next_power_of_two(7u) == 8u);
|
||||
CHECK(next_power_of_two(9u) == 16u);
|
||||
|
||||
// Test edge cases
|
||||
constexpr std::size_t max_power_of_2 = (std::numeric_limits<std::size_t>::max() >> 1) + 1;
|
||||
CHECK(next_power_of_two(std::numeric_limits<std::size_t>::max() - 1) == max_power_of_2); // Handling near overflow case
|
||||
CHECK(next_power_of_two(std::numeric_limits<std::size_t>::max() / 2 + 1) == max_power_of_2); // Largest possible input
|
||||
}
|
||||
|
||||
TEST_CASE("next_power_of_two_signed")
|
||||
{
|
||||
// Test with positive numbers that are already powers of two
|
||||
CHECK(next_power_of_two(1) == 1);
|
||||
CHECK(next_power_of_two(2) == 2);
|
||||
CHECK(next_power_of_two(4) == 4);
|
||||
CHECK(next_power_of_two(8) == 8);
|
||||
CHECK(next_power_of_two(16) == 16);
|
||||
CHECK(next_power_of_two(1024) == 1024);
|
||||
|
||||
// Test with positive numbers that are not powers of two
|
||||
CHECK(next_power_of_two(0) == 1);
|
||||
CHECK(next_power_of_two(3) == 4);
|
||||
CHECK(next_power_of_two(5) == 8);
|
||||
CHECK(next_power_of_two(6) == 8);
|
||||
CHECK(next_power_of_two(7) == 8);
|
||||
CHECK(next_power_of_two(9) == 16);
|
||||
|
||||
// Test edge cases
|
||||
constexpr int max_power_of_2_signed = (std::numeric_limits<int>::max() >> 1) + 1;
|
||||
CHECK(next_power_of_two(std::numeric_limits<int>::max() - 1) == max_power_of_2_signed); // Handling near overflow case for int
|
||||
CHECK(next_power_of_two(std::numeric_limits<int>::max() / 2 + 1) == max_power_of_2_signed); // Middle large input for int
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,419 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/backend/PatternFormatter.h"
|
||||
#include "quill/core/Common.h"
|
||||
#include "quill/core/MacroMetadata.h"
|
||||
#include <chrono>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
TEST_SUITE_BEGIN("PatternFormatter");
|
||||
|
||||
using namespace quill::detail;
|
||||
using namespace quill;
|
||||
|
||||
char const* thread_name = "test_thread";
|
||||
std::string_view process_id = "123";
|
||||
|
||||
TEST_CASE("default_pattern_formatter")
|
||||
{
|
||||
PatternFormatter default_pattern_formatter;
|
||||
|
||||
uint64_t const ts{1579815761000023021};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {} formatter {}",
|
||||
nullptr,
|
||||
LogLevel::Info,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = default_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
// Default pattern formatter is using local time to convert the timestamp to timezone, in this test we ignore the timestamp
|
||||
std::string const expected_string =
|
||||
"[31341] PatternFormatterTest.cpp:25 LOG_INFO test_logger This the pattern formatter "
|
||||
"1234\n";
|
||||
auto const found_expected = formatted_string.find(expected_string);
|
||||
REQUIRE_NE(found_expected, std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_message_only")
|
||||
{
|
||||
// Message only
|
||||
PatternFormatter custom_pattern_formatter{"%(log_level_id) %(message)", "%H:%M:%S.%Qns", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761000023000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 12.34);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
std::string const expected_string = "D This the 12.34 formatter pattern\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_timestamp_precision_nanoseconds")
|
||||
{
|
||||
// Custom pattern with part 1 and part 3
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761000023000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"01-23-2020 21:42:41.000023000 [31341] PatternFormatterTest.cpp:98 LOG_DEBUG test_logger "
|
||||
"This the 1234 formatter pattern [DOCTEST_ANON_FUNC_7]\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_timestamp_precision_microseconds")
|
||||
{
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%m-%d-%Y %H:%M:%S.%Qus", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761020123000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"01-23-2020 21:42:41.020123 [31341] PatternFormatterTest.cpp:136 LOG_DEBUG test_logger "
|
||||
"This the 1234 formatter pattern [DOCTEST_ANON_FUNC_9]\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_timestamp_precision_milliseconds")
|
||||
{
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%m-%d-%Y %H:%M:%S.%Qms", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761099000000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"01-23-2020 21:42:41.099 [31341] PatternFormatterTest.cpp:174 LOG_DEBUG test_logger This "
|
||||
"the 1234 formatter pattern [DOCTEST_ANON_FUNC_11]\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_timestamp_precision_none")
|
||||
{
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%m-%d-%Y %H:%M:%S", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761099220000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"01-23-2020 21:42:41 [31341] PatternFormatterTest.cpp:212 LOG_DEBUG test_logger This the "
|
||||
"1234 formatter pattern [DOCTEST_ANON_FUNC_13]\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_timestamp_strftime_reallocation_on_format_string_2")
|
||||
{
|
||||
// set a timestamp_format that will cause timestamp _formatted_date to re-allocate.
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%FT%T.%Qus%FT%T", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761099220000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"2020-01-23T21:42:41.0992202020-01-23T21:42:41 [31341] PatternFormatterTest.cpp:251 "
|
||||
"LOG_DEBUG test_logger This the 1234 formatter pattern [DOCTEST_ANON_FUNC_15]\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_timestamp_strftime_reallocation_when_adding_fractional_seconds")
|
||||
{
|
||||
// set a timestamp_format that will cause timestamp _formatted_date to re-allocate.
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%FT%T.%T.%Qus%FT%T", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761099220000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
for (size_t i = 0; i < 5; ++i)
|
||||
{
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"2020-01-23T21:42:41.21:42:41.0992202020-01-23T21:42:41 [31341] PatternFormatterTest.cpp:293 "
|
||||
"LOG_DEBUG test_logger This the 1234 formatter pattern [DOCTEST_ANON_FUNC_17]\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef QUILL_NO_EXCEPTIONS
|
||||
TEST_CASE("invalid_pattern")
|
||||
{
|
||||
// missing %)
|
||||
REQUIRE_THROWS_AS(
|
||||
PatternFormatter("%(time [%(thread_id)] %(file_name):%(line_number) %(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%H:%M:%S.%Qns", Timezone::GmtTime),
|
||||
quill::QuillError);
|
||||
|
||||
// invalid attribute %(invalid)
|
||||
REQUIRE_THROWS_AS(
|
||||
PatternFormatter("%(invalid) [%(thread_id)] %(file_name):%(line_number) %(log_level) %(logger) "
|
||||
"%(message) [%(caller_function)]",
|
||||
"%H:%M:%S.%Qns", Timezone::GmtTime),
|
||||
quill::QuillError);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("custom_pattern")
|
||||
{
|
||||
// Custom pattern with part 1 and part 2
|
||||
PatternFormatter custom_pattern_formatter{
|
||||
"%(time) [%(thread_id)] %(file_name):%(line_number) LOG_%(log_level) %(logger) %(message)",
|
||||
"%m-%d-%Y %H:%M:%S.%Qns", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761000023000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"01-23-2020 21:42:41.000023000 [31341] PatternFormatterTest.cpp:353 LOG_DEBUG test_logger "
|
||||
"This the 1234 formatter pattern\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_CASE("custom_pattern_part_3_no_format_specifiers")
|
||||
{
|
||||
// Custom pattern with a part 3 that has no format specifiers:
|
||||
// Part 1 - "|{}|{}|"
|
||||
// Part 3 - "|EOM|"
|
||||
PatternFormatter custom_pattern_formatter{"|LOG_%(log_level)|%(logger)|%(message)|EOM|",
|
||||
"%H:%M:%S", Timezone::GmtTime};
|
||||
|
||||
uint64_t const ts{1579815761000023000};
|
||||
char const* thread_id = "31341";
|
||||
std::string const logger_name = "test_logger";
|
||||
MacroMetadata macro_metadata{__FILE__ ":" QUILL_STRINGIFY(__LINE__),
|
||||
__func__,
|
||||
"This the {1} formatter {0}",
|
||||
nullptr,
|
||||
LogLevel::Debug,
|
||||
MacroMetadata::Event::Log};
|
||||
|
||||
// Format to a buffer
|
||||
fmtquill::memory_buffer log_msg;
|
||||
fmtquill::format_to(std::back_inserter(log_msg),
|
||||
fmtquill::runtime(macro_metadata.message_format()), "pattern", 1234);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> named_args;
|
||||
|
||||
auto const& formatted_buffer = custom_pattern_formatter.format(
|
||||
ts, thread_id, thread_name, process_id, logger_name, loglevel_to_string(macro_metadata.log_level()),
|
||||
macro_metadata, &named_args, std::string_view{log_msg.data(), log_msg.size()});
|
||||
|
||||
// Convert the buffer to a string
|
||||
std::string const formatted_string = fmtquill::to_string(formatted_buffer);
|
||||
|
||||
std::string const expected_string =
|
||||
"|LOG_DEBUG|test_logger|This the 1234 formatter pattern|EOM|\n";
|
||||
|
||||
REQUIRE_EQ(formatted_string, expected_string);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,49 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/backend/RdtscClock.h"
|
||||
#include "quill/core/Rdtsc.h"
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
TEST_SUITE_BEGIN("RdtscClock");
|
||||
|
||||
void check_wall_time_now(quill::detail::RdtscClock const& tsc_clock, size_t& failures)
|
||||
{
|
||||
std::chrono::milliseconds constexpr offset{10};
|
||||
|
||||
auto const wall_time_chrono = std::chrono::system_clock::now().time_since_epoch();
|
||||
auto const wall_time_tsc = std::chrono::nanoseconds{tsc_clock.time_since_epoch(quill::detail::rdtsc())};
|
||||
|
||||
auto const lower_bound = wall_time_chrono - offset;
|
||||
auto const upper_bound = wall_time_chrono + offset;
|
||||
|
||||
if (!((wall_time_tsc > lower_bound) && (wall_time_tsc < upper_bound)))
|
||||
{
|
||||
++failures;
|
||||
|
||||
if (failures > 1)
|
||||
{
|
||||
// wall_time_tsc is not between wall_time_chrono - 1 and wall_time_chrono + 1
|
||||
FAIL("wall_time_tsc: " << wall_time_tsc.count() << " lower_bound: " << lower_bound.count()
|
||||
<< " upper_bound: " << upper_bound.count() << "\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("wall_time")
|
||||
{
|
||||
quill::detail::RdtscClock const tsc_clock{std::chrono::milliseconds{1200}};
|
||||
|
||||
constexpr size_t num_reps{10};
|
||||
size_t failures{0};
|
||||
|
||||
for (size_t i = 1; i <= num_reps; ++i)
|
||||
{
|
||||
check_wall_time_now(tsc_clock, failures);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{i * 100});
|
||||
}
|
||||
|
||||
REQUIRE_LE(failures, 1);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,68 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/core/SinkManager.h"
|
||||
#include "quill/sinks/FileSink.h"
|
||||
#include <cstdio>
|
||||
|
||||
TEST_SUITE_BEGIN("SinkManager");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("subscribe_get_active_different_sinks")
|
||||
{
|
||||
std::string file_1 = "file1.log";
|
||||
std::string file_2 = "file2.log";
|
||||
|
||||
{
|
||||
// Create a file sink
|
||||
std::shared_ptr<Sink> file_sink_1_a = SinkManager::instance().create_or_get_sink<quill::FileSink>(
|
||||
file_1,
|
||||
[]()
|
||||
{
|
||||
quill::FileSinkConfig cfg;
|
||||
cfg.set_open_mode('w');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// Request the same sink
|
||||
std::shared_ptr<Sink> file_sink_1_b = SinkManager::instance().create_or_get_sink<quill::FileSink>(
|
||||
file_1,
|
||||
[]()
|
||||
{
|
||||
quill::FileSinkConfig cfg;
|
||||
cfg.set_open_mode('a');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
std::shared_ptr<Sink> file_sink_1_c = SinkManager::instance().get_sink(file_1);
|
||||
|
||||
// Request a new sink of the same file
|
||||
std::shared_ptr<Sink> file_sink_3 = SinkManager::instance().create_or_get_sink<quill::FileSink>(
|
||||
file_2,
|
||||
[]()
|
||||
{
|
||||
quill::FileSinkConfig cfg;
|
||||
cfg.set_open_mode('a');
|
||||
return cfg;
|
||||
}(),
|
||||
FileEventNotifier{});
|
||||
|
||||
// Compare the pointers
|
||||
REQUIRE_EQ(file_sink_1_a.get(), file_sink_1_b.get());
|
||||
REQUIRE_EQ(file_sink_1_a.get(), file_sink_1_c.get());
|
||||
REQUIRE_NE(file_sink_1_a.get(), file_sink_3.get());
|
||||
REQUIRE_EQ(SinkManager::instance().cleanup_unused_sinks(), 0);
|
||||
}
|
||||
|
||||
// Pointers are out of score and we except them cleaned up
|
||||
REQUIRE_EQ(SinkManager::instance().cleanup_unused_sinks(), 2);
|
||||
|
||||
std::remove(file_1.data());
|
||||
std::remove(file_2.data());
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,449 @@
|
|||
#include "quill/backend/StringFromTime.h"
|
||||
#include "DocTestExtensions.h"
|
||||
#include "doctest/doctest.h"
|
||||
#include <ctime>
|
||||
|
||||
TEST_SUITE_BEGIN("StringFromTime");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_format_time")
|
||||
{
|
||||
std::string fmt2 = "%H:%M:%S";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 500'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_format_I")
|
||||
{
|
||||
std::string fmt2 = "%I:%M:%S%p";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 500'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_fallback_to_strftime")
|
||||
{
|
||||
// In this edge case we pass a timestamp that is back in time from our cached timestamp value.
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// This will create the StringFromTime class and pre-format a string for the timestamp now
|
||||
std::string fmt2 = "%Y-%m-%dT%H:%M:%SZ";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::GmtTime);
|
||||
|
||||
// Ask StringFromTime to format timestamps in the past
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 500'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::gmtime_rs(&raw_ts, &time_info);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Decrement the timestamp for the next loop
|
||||
raw_ts -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_main_format")
|
||||
{
|
||||
std::string fmt2 = "%Y-%m-%dT%H:%M:%SZ";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 600'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_gmtime_main_format")
|
||||
{
|
||||
std::string fmt2 = "%Y-%m-%dT%H:%M:%SZ";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::GmtTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 600'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::gmtime_rs(&raw_ts, &time_info);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("string_from_time_localtime_main_format_increment_ts")
|
||||
{
|
||||
std::string fmt2 = "%Y-%m-%dT%H:%M:%SZ";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 10'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
// This test increments the ts by a huge amount trying to mimic e.g. system clock changes
|
||||
raw_ts += 7200;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_empty_cached_indexes")
|
||||
{
|
||||
// try with a format that doesn't have hours, minutes, seconds
|
||||
std::string fmt2 = "%Y-%m-%d";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 500'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), &time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
// The following tests don't run on windows because the format identifiers are not supported.
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_format_l")
|
||||
{
|
||||
std::string fmt2 = "%l:%M:%S%p";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 500'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm* time_info;
|
||||
time_info = std::localtime(&raw_ts);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_format_k")
|
||||
{
|
||||
std::string fmt2 = "%k:%M:%S%p";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 500'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm* time_info;
|
||||
time_info = std::localtime(&raw_ts);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("string_from_time_localtime_format_s")
|
||||
{
|
||||
std::string fmt2 = "%Y-%m-%d %s";
|
||||
StringFromTime string_from_time;
|
||||
|
||||
string_from_time.init(fmt2, Timezone::LocalTime);
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
// Try for a few timestamps
|
||||
for (uint32_t i = 0; i <= 100'000; ++i)
|
||||
{
|
||||
// Get the time from string from time
|
||||
auto const& time_s1 = string_from_time.format_timestamp(raw_ts);
|
||||
|
||||
// Get the time from strftime
|
||||
std::tm* time_info;
|
||||
time_info = std::localtime(&raw_ts);
|
||||
char buffer[256];
|
||||
std::strftime(buffer, 256, fmt2.data(), time_info);
|
||||
auto const time_s2 = std::string{buffer};
|
||||
|
||||
REQUIRE_STREQ(time_s1.data(), time_s2.data());
|
||||
|
||||
// Increment the timestamp for the next loop
|
||||
raw_ts += 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
class StringFromTimeMock : public quill::detail::StringFromTime
|
||||
{
|
||||
public:
|
||||
static time_t next_noon_or_midnight_timestamp(time_t timestamp, Timezone timezone) noexcept
|
||||
{
|
||||
return quill::detail::StringFromTime::_next_noon_or_midnight_timestamp(timestamp, timezone);
|
||||
}
|
||||
|
||||
static time_t nearest_hour_timestamp(time_t timestamp) noexcept
|
||||
{
|
||||
return quill::detail::StringFromTime::_nearest_hour_timestamp(timestamp);
|
||||
}
|
||||
|
||||
static time_t next_hour_timestamp(time_t timestamp) noexcept
|
||||
{
|
||||
return quill::detail::StringFromTime::_next_hour_timestamp(timestamp);
|
||||
}
|
||||
|
||||
static std::vector<char> safe_strftime(char const* format_string, time_t timestamp, Timezone timezone)
|
||||
{
|
||||
return quill::detail::StringFromTime::_safe_strftime(format_string, timestamp, timezone);
|
||||
}
|
||||
};
|
||||
|
||||
/***/
|
||||
TEST_CASE("next_noon_or_midnight_timestamp")
|
||||
{
|
||||
// We do not test local because if we hardcode an expected_timestamp in our local timezone
|
||||
// it can be different in another system
|
||||
|
||||
{
|
||||
// Noon utc
|
||||
time_t constexpr timestamp{1599033200};
|
||||
time_t constexpr expected_timestamp{1599048000};
|
||||
time_t const res = StringFromTimeMock::next_noon_or_midnight_timestamp(timestamp, Timezone::GmtTime);
|
||||
REQUIRE_EQ(res, expected_timestamp);
|
||||
}
|
||||
|
||||
{
|
||||
// Midnight utc
|
||||
time_t constexpr timestamp{1599079200};
|
||||
time_t constexpr expected_timestamp{1599091200};
|
||||
time_t const res = StringFromTimeMock::next_noon_or_midnight_timestamp(timestamp, Timezone::GmtTime);
|
||||
REQUIRE_EQ(res, expected_timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("nearest_hour_timestamp")
|
||||
{
|
||||
time_t constexpr timestamp = 1599473669;
|
||||
time_t constexpr expected_timestamp = 1599472800;
|
||||
REQUIRE_EQ(StringFromTimeMock::nearest_hour_timestamp(timestamp), expected_timestamp);
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("next_hour_timestamp")
|
||||
{
|
||||
time_t constexpr timestamp = 1599473669;
|
||||
time_t constexpr expected_timestamp = 1599476400;
|
||||
REQUIRE_EQ(StringFromTimeMock::next_hour_timestamp(timestamp), expected_timestamp);
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("safe_strftime_resize")
|
||||
{
|
||||
// e.g. "Monday September 2020 (09/07/20) 15:37 EEST"
|
||||
constexpr char const* format_string = "%A %B %Y (%x) %R %Z";
|
||||
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
|
||||
// we will format a string greater than 32
|
||||
char expected_result[256];
|
||||
std::strftime(expected_result, 256, format_string, &time_info);
|
||||
|
||||
// Also try our version
|
||||
std::string const safe_strftime_result =
|
||||
std::string{StringFromTimeMock::safe_strftime(format_string, raw_ts, Timezone::LocalTime).data()};
|
||||
|
||||
REQUIRE_STREQ(expected_result, safe_strftime_result.data());
|
||||
}
|
||||
|
||||
TEST_CASE("safe_strftime_empty")
|
||||
{
|
||||
// Get the timestamp now
|
||||
time_t raw_ts;
|
||||
std::time(&raw_ts);
|
||||
|
||||
std::tm time_info{};
|
||||
quill::detail::localtime_rs(&raw_ts, &time_info);
|
||||
|
||||
// we will format a string greater than 32
|
||||
char expected_result[256];
|
||||
std::strftime(expected_result, 256, "", &time_info);
|
||||
|
||||
// Also try our version
|
||||
std::string const safe_strftime_result =
|
||||
std::string{StringFromTimeMock::safe_strftime("", raw_ts, Timezone::LocalTime).data()};
|
||||
|
||||
REQUIRE_STREQ(expected_result, safe_strftime_result.data());
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,115 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/core/FrontendOptions.h"
|
||||
#include "quill/core/ThreadContextManager.h"
|
||||
#include <array>
|
||||
#include <thread>
|
||||
|
||||
TEST_SUITE_BEGIN("ThreadContextManager");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("add_and_remove_thread_contexts")
|
||||
{
|
||||
// 1) Test that every time a new thread context is added to the thread context shared collection
|
||||
// and to the thread context cache when a new thread spawns and we load the cache
|
||||
// 2) Test that the thread context is invalidated when the thread that created it completes
|
||||
// 3) Test that when the threads complete they are removed
|
||||
|
||||
constexpr uint32_t tries = 4;
|
||||
for (uint32_t k = 0; k < tries; ++k)
|
||||
{
|
||||
constexpr size_t num_threads{25};
|
||||
std::array<std::thread, num_threads> threads;
|
||||
std::array<std::atomic<bool>, num_threads> terminate_flag{};
|
||||
std::fill(terminate_flag.begin(), terminate_flag.end(), false);
|
||||
|
||||
std::atomic<uint32_t> threads_started{0};
|
||||
|
||||
// spawn x number of threads
|
||||
for (size_t i = 0; i < threads.size(); ++i)
|
||||
{
|
||||
auto& thread_terminate_flag = terminate_flag[i];
|
||||
threads[i] = std::thread(
|
||||
[&thread_terminate_flag, &threads_started]()
|
||||
{
|
||||
// create a context for that thread
|
||||
ThreadContext* tc = get_local_thread_context<FrontendOptions>();
|
||||
|
||||
REQUIRE(tc->has_unbounded_queue_type());
|
||||
REQUIRE(tc->has_blocking_queue());
|
||||
|
||||
REQUIRE_FALSE(tc->has_bounded_queue_type());
|
||||
REQUIRE_FALSE(tc->has_dropping_queue());
|
||||
|
||||
threads_started.fetch_add(1);
|
||||
while (!thread_terminate_flag.load())
|
||||
{
|
||||
// loop waiting for main to signal
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// main wait for all of them to start
|
||||
while (threads_started.load() < num_threads)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{1});
|
||||
}
|
||||
|
||||
// Check we have exactly as many thread contexts as the amount of threads in our backend cache
|
||||
uint64_t thread_ctx_cnt{0};
|
||||
|
||||
// Check all thread contexts in the backend thread contexts cache
|
||||
ThreadContextManager::instance().for_each_thread_context(
|
||||
[&thread_ctx_cnt](ThreadContext const* tc)
|
||||
{
|
||||
REQUIRE(tc->is_valid_context());
|
||||
REQUIRE(tc->get_spsc_queue<FrontendOptions::queue_type>().empty());
|
||||
++thread_ctx_cnt;
|
||||
});
|
||||
|
||||
REQUIRE_EQ(thread_ctx_cnt, num_threads);
|
||||
REQUIRE_FALSE(ThreadContextManager::instance().has_invalid_thread_context());
|
||||
|
||||
// terminate all threads - This will invalidate all the thread contexts
|
||||
for (size_t j = 0; j < threads.size(); ++j)
|
||||
{
|
||||
terminate_flag[j].store(true);
|
||||
threads[j].join();
|
||||
}
|
||||
|
||||
REQUIRE(ThreadContextManager::instance().has_invalid_thread_context());
|
||||
|
||||
// Now check all thread contexts still exist but they are invalided and then remove them
|
||||
|
||||
REQUIRE(ThreadContextManager::instance().has_invalid_thread_context());
|
||||
|
||||
// For this we use the old cache avoiding to update it - This never happens in the real logger
|
||||
std::vector<ThreadContext const*> tc_cache;
|
||||
ThreadContextManager::instance().for_each_thread_context(
|
||||
[&tc_cache](ThreadContext const* tc)
|
||||
{
|
||||
REQUIRE_FALSE(tc->is_valid_context());
|
||||
REQUIRE(tc->get_spsc_queue<FrontendOptions::queue_type>().empty());
|
||||
tc_cache.push_back(tc);
|
||||
});
|
||||
|
||||
// Remove them
|
||||
for (ThreadContext const* tc : tc_cache)
|
||||
{
|
||||
ThreadContextManager::instance().remove_shared_invalidated_thread_context(tc);
|
||||
}
|
||||
|
||||
// Check all are removed
|
||||
bool tc_found = false;
|
||||
ThreadContextManager::instance().for_each_thread_context([&tc_found](ThreadContext const* tc)
|
||||
{ tc_found = true; });
|
||||
|
||||
REQUIRE_FALSE(tc_found);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,183 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "misc/DocTestExtensions.h"
|
||||
#include "quill/backend/TimestampFormatter.h"
|
||||
#include "quill/core/QuillError.h"
|
||||
|
||||
TEST_SUITE_BEGIN("TimestampFormatter");
|
||||
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("simple_format_string")
|
||||
{
|
||||
// invalid format strings
|
||||
#if !defined(QUILL_NO_EXCEPTIONS)
|
||||
REQUIRE_THROWS_AS(TimestampFormatter ts_formatter{"%I:%M%p%Qms%S%Qus z"}, quill::QuillError);
|
||||
REQUIRE_THROWS_AS(TimestampFormatter ts_formatter{"%I:%M%p%Qms%S%Qus%Qns z"}, quill::QuillError);
|
||||
REQUIRE_THROWS_AS(TimestampFormatter ts_formatter{"%I:%M%p%S%Qus%Qns z"}, quill::QuillError);
|
||||
#endif
|
||||
|
||||
// valid simple string
|
||||
REQUIRE_NOTHROW(TimestampFormatter ts_formatter{"%I:%M%p%S%Qns z"});
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("format_string_no_additional_specifier")
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887987654321};
|
||||
|
||||
// simple formats without any ms/us/ns specifiers
|
||||
{
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07");
|
||||
}
|
||||
|
||||
{
|
||||
TimestampFormatter ts_formatter{"%F %H:%M:%S", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "2020-04-17 22:18:07");
|
||||
}
|
||||
|
||||
// large simple string to cause reallocation
|
||||
{
|
||||
TimestampFormatter ts_formatter{"%A %B %d %T %Y %F", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "Friday April 17 22:18:07 2020 2020-04-17");
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("format_string_with_millisecond_precision")
|
||||
{
|
||||
// simple
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887987654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qms", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.987");
|
||||
}
|
||||
|
||||
// with double formatting
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887803654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qms %D", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.803 04/17/20");
|
||||
}
|
||||
|
||||
// with double formatting 2
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887023654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qms-%G", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.023-2020");
|
||||
}
|
||||
|
||||
// with zeros
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887009654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qms", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.009");
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("format_string_with_microsecond_precision")
|
||||
{
|
||||
// simple
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887987654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qus", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.987654");
|
||||
}
|
||||
|
||||
// with double formatting
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887803654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qus %D", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.803654 04/17/20");
|
||||
}
|
||||
|
||||
// with double formatting 2
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887010654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qus-%G", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.010654-2020");
|
||||
}
|
||||
|
||||
// with zeros
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887000004321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qus", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.000004");
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("format_string_with_nanosecond_precision")
|
||||
{
|
||||
// simple
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887987654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qns", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.987654321");
|
||||
}
|
||||
|
||||
// with double formatting
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887803654320};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qns %D", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.803654320 04/17/20");
|
||||
}
|
||||
|
||||
// with double formatting 2
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887000654321};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qns-%G", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.000654321-2020");
|
||||
}
|
||||
|
||||
// with zeros
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887000000009};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qns", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.000000009");
|
||||
}
|
||||
|
||||
// with max
|
||||
{
|
||||
std::chrono::nanoseconds constexpr timestamp{1587161887999999999};
|
||||
TimestampFormatter ts_formatter{"%H:%M:%S.%Qns", quill::Timezone::GmtTime};
|
||||
|
||||
auto const& result = ts_formatter.format_timestamp(timestamp);
|
||||
REQUIRE_STREQ(result.data(), "22:18:07.999999999");
|
||||
}
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,254 @@
|
|||
#include "DocTestExtensions.h"
|
||||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/backend/TransitEventBuffer.h"
|
||||
|
||||
TEST_SUITE_BEGIN("TransitEventBuffer");
|
||||
|
||||
using namespace quill;
|
||||
using namespace quill::detail;
|
||||
|
||||
/***/
|
||||
TEST_CASE("transit_event_bounded_buffer")
|
||||
{
|
||||
BoundedTransitEventBuffer bte{4};
|
||||
REQUIRE_EQ(bte.capacity(), 4);
|
||||
|
||||
for (size_t i = 0; i < 12; ++i)
|
||||
{
|
||||
REQUIRE_FALSE(bte.front());
|
||||
REQUIRE_EQ(bte.size(), 0);
|
||||
|
||||
{
|
||||
TransitEvent* te1 = bte.back();
|
||||
REQUIRE(te1);
|
||||
|
||||
te1->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te1->named_args->clear();
|
||||
te1->named_args->emplace_back(std::string{"test1"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 1);
|
||||
|
||||
{
|
||||
TransitEvent* te2 = bte.back();
|
||||
REQUIRE(te2);
|
||||
|
||||
te2->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te2->named_args->clear();
|
||||
te2->named_args->emplace_back(std::string{"test2"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 2);
|
||||
|
||||
{
|
||||
TransitEvent* te3 = bte.back();
|
||||
REQUIRE(te3);
|
||||
|
||||
te3->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te3->named_args->clear();
|
||||
te3->named_args->emplace_back(std::string{"test3"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 3);
|
||||
|
||||
{
|
||||
TransitEvent* te4 = bte.back();
|
||||
REQUIRE(te4);
|
||||
|
||||
te4->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te4->named_args->clear();
|
||||
te4->named_args->emplace_back(std::string{"test4"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 4);
|
||||
|
||||
// read
|
||||
{
|
||||
TransitEvent* te1 = bte.front();
|
||||
REQUIRE(te1);
|
||||
std::string const expected = std::string{"test1"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te1->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 3);
|
||||
|
||||
{
|
||||
TransitEvent* te2 = bte.front();
|
||||
REQUIRE(te2);
|
||||
std::string const expected = std::string{"test2"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te2->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 2);
|
||||
|
||||
{
|
||||
TransitEvent* te3 = bte.front();
|
||||
REQUIRE(te3);
|
||||
std::string const expected = std::string{"test3"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te3->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 1);
|
||||
|
||||
{
|
||||
TransitEvent* te4 = bte.front();
|
||||
REQUIRE(te4);
|
||||
std::string const expected = std::string{"test4"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te4->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 0);
|
||||
REQUIRE_FALSE(bte.front());
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("transit_event_bounded_buffer_integer_overflow")
|
||||
{
|
||||
BoundedTransitEventBufferImpl<uint8_t> bte{128};
|
||||
size_t constexpr iterations = static_cast<size_t>(std::numeric_limits<uint8_t>::max()) * 8ull;
|
||||
|
||||
for (size_t i = 0; i < iterations; ++i)
|
||||
{
|
||||
REQUIRE_EQ(bte.size(), 0);
|
||||
|
||||
{
|
||||
TransitEvent* te = bte.back();
|
||||
REQUIRE(te);
|
||||
|
||||
te->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te->named_args->clear();
|
||||
te->named_args->emplace_back(std::string{"test"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), 1);
|
||||
|
||||
// read
|
||||
{
|
||||
TransitEvent* te = bte.front();
|
||||
REQUIRE(te);
|
||||
std::string const expected = std::string{"test"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("transit_event_unbounded_buffer")
|
||||
{
|
||||
UnboundedTransitEventBuffer bte{4};
|
||||
|
||||
REQUIRE_FALSE(bte.front());
|
||||
REQUIRE(bte.empty());
|
||||
REQUIRE_EQ(bte.size(), 0);
|
||||
|
||||
for (size_t i = 0; i < 128; ++i)
|
||||
{
|
||||
{
|
||||
TransitEvent* te1 = bte.back();
|
||||
REQUIRE(te1);
|
||||
|
||||
te1->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te1->named_args->clear();
|
||||
te1->named_args->emplace_back(std::string{"test1"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), i * 4 + 1);
|
||||
|
||||
{
|
||||
TransitEvent* te2 = bte.back();
|
||||
REQUIRE(te2);
|
||||
|
||||
te2->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te2->named_args->clear();
|
||||
te2->named_args->emplace_back(std::string{"test2"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), i * 4 + 2);
|
||||
|
||||
{
|
||||
TransitEvent* te3 = bte.back();
|
||||
REQUIRE(te3);
|
||||
|
||||
te3->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te3->named_args->clear();
|
||||
te3->named_args->emplace_back(std::string{"test3"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), i * 4 + 3);
|
||||
|
||||
{
|
||||
TransitEvent* te4 = bte.back();
|
||||
REQUIRE(te4);
|
||||
|
||||
te4->named_args = std::make_unique<std::vector<std::pair<std::string, std::string>>>();
|
||||
te4->named_args->clear();
|
||||
te4->named_args->emplace_back(std::string{"test4"} + std::to_string(i), std::string{});
|
||||
bte.push_back();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), i * 4 + 4);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 128; ++i)
|
||||
{
|
||||
// read
|
||||
{
|
||||
TransitEvent* te1 = bte.front();
|
||||
REQUIRE(te1);
|
||||
std::string const expected = std::string{"test1"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te1->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), (128 - i) * 4 - 1);
|
||||
|
||||
{
|
||||
TransitEvent* te2 = bte.front();
|
||||
REQUIRE(te2);
|
||||
std::string const expected = std::string{"test2"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te2->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), (128 - i) * 4 - 2);
|
||||
|
||||
{
|
||||
TransitEvent* te3 = bte.front();
|
||||
REQUIRE(te3);
|
||||
std::string const expected = std::string{"test3"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te3->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), (128 - i) * 4 - 3);
|
||||
|
||||
{
|
||||
TransitEvent* te4 = bte.front();
|
||||
REQUIRE(te4);
|
||||
std::string const expected = std::string{"test4"} + std::to_string(i);
|
||||
REQUIRE_STREQ((*te4->named_args)[0].first.data(), expected.data());
|
||||
bte.pop_front();
|
||||
}
|
||||
|
||||
REQUIRE_EQ(bte.size(), (128 - i) * 4 - 4);
|
||||
}
|
||||
|
||||
REQUIRE_FALSE(bte.front());
|
||||
REQUIRE(bte.empty());
|
||||
REQUIRE_EQ(bte.size(), 0);
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/core/UnboundedSPSCQueue.h"
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
TEST_SUITE_BEGIN("UnboundedQueue");
|
||||
|
||||
using namespace quill::detail;
|
||||
|
||||
TEST_CASE("unbounded_queue_read_write_multithreaded_plain_ints")
|
||||
{
|
||||
UnboundedSPSCQueue buffer{1024};
|
||||
|
||||
std::thread producer_thread(
|
||||
[&buffer]()
|
||||
{
|
||||
for (uint32_t wrap_cnt = 0; wrap_cnt < 20; ++wrap_cnt)
|
||||
{
|
||||
for (uint32_t i = 0; i < 8192; ++i)
|
||||
{
|
||||
auto* write_buffer = buffer.prepare_write(sizeof(uint32_t), quill::QueueType::UnboundedBlocking);
|
||||
|
||||
while (!write_buffer)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{2});
|
||||
write_buffer = buffer.prepare_write(sizeof(uint32_t), quill::QueueType::UnboundedBlocking);
|
||||
}
|
||||
|
||||
std::memcpy(write_buffer, &i, sizeof(uint32_t));
|
||||
buffer.finish_write(sizeof(uint32_t));
|
||||
buffer.commit_write();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Delay creating the consumer thread
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds{300});
|
||||
|
||||
std::thread consumer_thread(
|
||||
[&buffer]()
|
||||
{
|
||||
for (uint32_t wrap_cnt = 0; wrap_cnt < 20; ++wrap_cnt)
|
||||
{
|
||||
for (uint32_t i = 0; i < 8192; ++i)
|
||||
{
|
||||
auto read_result = buffer.prepare_read();
|
||||
while (!read_result.read_pos)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::microseconds{2});
|
||||
read_result = buffer.prepare_read();
|
||||
}
|
||||
|
||||
auto const value = reinterpret_cast<uint32_t const*>(read_result.read_pos);
|
||||
REQUIRE_EQ(*value, i);
|
||||
buffer.finish_read(sizeof(uint32_t));
|
||||
buffer.commit_read();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
producer_thread.join();
|
||||
consumer_thread.join();
|
||||
REQUIRE(buffer.empty());
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
|
@ -0,0 +1,55 @@
|
|||
#include "doctest/doctest.h"
|
||||
|
||||
#include "quill/Utility.h"
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
|
||||
TEST_SUITE_BEGIN("Utility");
|
||||
|
||||
/***/
|
||||
TEST_CASE("ascii_string_to_hex_1")
|
||||
{
|
||||
std::string buffer = "Hello World";
|
||||
std::string const result = quill::utility::to_hex(buffer.data(), buffer.length());
|
||||
std::string const expected = "48 65 6C 6C 6F 20 57 6F 72 6C 64";
|
||||
REQUIRE_EQ(result, expected);
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("ascii_string_to_hex_2")
|
||||
{
|
||||
std::string buffer = "A longer ASCII text";
|
||||
std::string const result = quill::utility::to_hex(buffer.data(), buffer.length());
|
||||
std::string const expected = "41 20 6C 6F 6E 67 65 72 20 41 53 43 49 49 20 74 65 78 74";
|
||||
REQUIRE_EQ(result, expected);
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("ascii_string_to_hex_2_const")
|
||||
{
|
||||
std::string const buffer = "A longer ASCII text";
|
||||
std::string const result = quill::utility::to_hex(buffer.data(), buffer.length());
|
||||
std::string const expected = "41 20 6C 6F 6E 67 65 72 20 41 53 43 49 49 20 74 65 78 74";
|
||||
REQUIRE_EQ(result, expected);
|
||||
}
|
||||
|
||||
/***/
|
||||
TEST_CASE("byte_buffer_to_hex_1")
|
||||
{
|
||||
uint32_t input = 431234;
|
||||
unsigned char buffer[4];
|
||||
std::memcpy(buffer, reinterpret_cast<char*>(&input), sizeof(input));
|
||||
|
||||
// non const overload
|
||||
std::string const result = quill::utility::to_hex(buffer, 4);
|
||||
std::string const expected = "82 94 06 00";
|
||||
REQUIRE_EQ(result, expected);
|
||||
|
||||
// const overload
|
||||
unsigned char* const buffer_const = &buffer[0];
|
||||
std::string const result_2 = quill::utility::to_hex(buffer_const, 4);
|
||||
REQUIRE_EQ(result_2, expected);
|
||||
}
|
||||
|
||||
TEST_SUITE_END();
|
Loading…
Add table
Add a link
Reference in a new issue