Migrates the project from bazel to cmake and copies tinytest into the project temporarily.

This commit is contained in:
Tom Hicks
2025-04-08 15:05:58 -07:00
parent 36fed9b926
commit 40121ff39a
26 changed files with 2259 additions and 172 deletions

34
tests/CMakeLists.txt Normal file
View File

@@ -0,0 +1,34 @@
# Enable testing
enable_testing()
# Define the ansi_escapes_test executable
add_executable(ansi_escapes_test ansi_escapes_test.cpp)
target_link_libraries(ansi_escapes_test PRIVATE ansi_escapes tinytest)
add_test(NAME ansi_escapes_test COMMAND ansi_escapes_test)
# Define the console_logger_test executable
add_executable(console_logger_test console_logger_test.cpp)
target_link_libraries(console_logger_test PRIVATE console_logger tinytest)
add_test(NAME console_logger_test COMMAND console_logger_test)
# Define the logger_test executable
add_executable(logger_test logger_test.cpp)
target_link_libraries(logger_test PRIVATE logger tinytest)
add_test(NAME logger_test COMMAND logger_test)
# Define the pretty_print_test executable
add_executable(pretty_print_test pretty_print_test.cpp)
target_link_libraries(pretty_print_test PRIVATE pretty_print tinytest)
add_test(NAME pretty_print_test COMMAND pretty_print_test)
# Define the windows_logger_test executable only for Windows
if(WIN32)
add_executable(windows_logger_test windows_logger_test.cpp)
target_link_libraries(windows_logger_test PRIVATE windows_logger tinytest)
add_test(NAME windows_logger_test COMMAND windows_logger_test)
endif()
# Define the tinytest_test executable
add_executable(tinytest_test tinytest_test.cpp)
target_link_libraries(tinytest_test PRIVATE tinytest gtest_main gtest gmock)
add_test(NAME tinytest_test COMMAND tinytest_test)

256
tests/ansi_escapes_test.cpp Normal file
View File

@@ -0,0 +1,256 @@
/**********************************************************************************************************************
* *
* @file ansi_escapes_test.cpp *
* *
* @brief Defines constants and functions for working with screen colors. *
* @copyright Copyright (C) 2023 by Tom Hicks <headhunter3@gmail.com> *
* *
* Licensed under the MIT license see below for details. *
* *
* MIT License *
* *
* Copyright (c) 2023 Tom Hicks <headhunter3@gmail.com> *
* *
* 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. *
* *
**********************************************************************************************************************/
// clang-format off
#include "ansi_escapes.h"
#include "tinytest.h"
// clang-format on
#include <regex>
#include <sstream>
#include <string>
#include <string_view>
#include <tuple>
namespace {
using std::make_tuple;
using std::ostream;
using std::ostringstream;
using std::string;
using std::string_view;
using TinyTest::ExecuteSuite;
using TinyTest::MakeTest;
using TinyTest::MakeTestSuite;
using TinyTest::TestResults;
} // End namespace
string filter(const string &text) {
std::regex pattern("\033");
return std::regex_replace(text, pattern, "\\033");
}
TestResults test_GetRedComponent() {
return ExecuteSuite(
MakeTestSuite("CPPUtils::GetRedComponent(uint32_t)",
CPPUtils::GetRedComponent,
{
MakeTest("should get the red component 0x34 from 0x12345678", 0x34U, make_tuple(0x12345678U)),
MakeTest("should get the red component 0x56 from 0x34567890", 0x56U, make_tuple(0x34567890U)),
}));
}
TestResults test_GetGreenComponent() {
return ExecuteSuite(
MakeTestSuite("CPPUtils::GetGreenComponent(uint32_t)",
CPPUtils::GetGreenComponent,
{
MakeTest("should get the green component 0x56 from 0x12345678", 0x56U, make_tuple(0x12345678U)),
MakeTest("should get the green component 0x78 from 0x34567890", 0x78U, make_tuple(0x34567890U)),
}));
}
TestResults test_GetBlueComponent() {
return ExecuteSuite(
MakeTestSuite("CPPUtils::GetBlueComponent(uint32_t)",
CPPUtils::GetBlueComponent,
{
MakeTest("should get the blue component 0x78 from 0x12345678", 0x78, make_tuple(0x12345678)),
MakeTest("should get the blue component 0x90 from 0x34567890", 0x90, make_tuple(0x34567890)),
}));
}
TestResults test_EscapeWithBasicString() {
auto function_to_test = [](string text) {
ostringstream os;
CPPUtils::Escape(os, text);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::Escape(string)",
function_to_test,
{
MakeTest("should escape \"asdf\" to \"\\033[asdfm\"", (string) "\033[asdfm", make_tuple("asdf")),
MakeTest("should escape \"fdsa\" to \"\\033[fdsam\"", (string) "\033[fdsam", make_tuple("fdsa")),
MakeTest("should escape \"1;2;3\" to \"\\033[1;2;3m\"", (string) "\033[1;2;3m", make_tuple("1;2;3")),
}));
}
TestResults test_EscapeWithBasicStringView() {
auto function_to_test = [](string_view text) {
ostringstream os;
CPPUtils::Escape(os, text);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::Escape(string_view)",
function_to_test,
{
MakeTest("should escape \"asdf\" to \"\\033[asdfm\"", (string) "\033[asdfm", make_tuple("asdf")),
MakeTest("should escape \"fdsa\" to \"\\033[fdsam\"", (string) "\033[fdsam", make_tuple("fdsa")),
MakeTest("should escape \"1;2;3\" to \"\\033[1;2;3m\"", (string) "\033[1;2;3m", make_tuple("1;2;3")),
}));
}
TestResults test_EscapeWithConstCharStar() {
auto function_to_test = [](const char *text) {
ostringstream os;
CPPUtils::Escape(os, text);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::Escape(const char*)",
function_to_test,
{
MakeTest("should escape \"asdf\" to \"\\033[asdfm\"", (string) "\033[asdfm", make_tuple("asdf")),
MakeTest("should escape \"fdsa\" to \"\\033[fdsam\"", (string) "\033[fdsam", make_tuple("fdsa")),
MakeTest("should escape \"1;2;3\" to \"\\033[1;2;3m\"", (string) "\033[1;2;3m", make_tuple("1;2;3")),
}));
}
TestResults test_ForegroundColor8Bit() {
auto function_to_test = [](uint8_t color) {
ostringstream os;
CPPUtils::ForegroundColor8Bit(os, color);
return os.str();
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::ForegroundColor8Bit(uint8_t)",
function_to_test,
{
MakeTest("should write \"\\033[38;5;7m\"", (string) "\033[38;5;7m", make_tuple(0x07U)),
MakeTest("should write \"\\033[38;5;1m\"", (string) "\033[38;5;1m", make_tuple(0x01U)),
MakeTest("should write \"\\033[38;5;11m\"", (string) "\033[38;5;11m", make_tuple(0x0BU)),
}));
}
TestResults test_BackgroundColor8Bit() {
auto function_to_test = [](uint8_t color) {
ostringstream os;
CPPUtils::BackgroundColor8Bit(os, color);
return os.str();
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::BackgroundColor8Bit(uint8_t)",
function_to_test,
{
MakeTest("should write \"\\033[48;5;7m\"", (string) "\033[48;5;7m", make_tuple(0x07U)),
MakeTest("should write \"\\033[48;5;1m\"", (string) "\033[48;5;1m", make_tuple(0x01U)),
MakeTest("should write \"\\033[48;5;11m\"", (string) "\033[48;5;11m", make_tuple(0x0BU)),
}));
}
TestResults test_ForegroundTrueColorWithUInt32() {
auto function_to_test = [](uint32_t color) {
ostringstream os;
CPPUtils::ForegroundTrueColor(os, color);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::ForegroundTrueColor(uint32_t)",
function_to_test,
{
MakeTest("should write \"\\033[38;2;21;69;136m\"", (string) "\033[38;2;21;69;136m", make_tuple(0x00154588)),
}));
}
TestResults test_BackgroundTrueColorWithUInt32() {
auto function_to_test = [](uint32_t color) {
ostringstream os;
CPPUtils::BackgroundTrueColor(os, color);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::BackgroundTrueColor(uint32_t)",
function_to_test,
{
MakeTest("should write \"\\033[48;2;21;69;136m\"", (string) "\033[48;2;21;69;136m", make_tuple(0x00154588)),
}));
}
TestResults test_ForegroundTrueColorWith3UInt8() {
auto function_to_test = [](uint8_t red, uint8_t green, uint8_t blue) {
ostringstream os;
CPPUtils::ForegroundTrueColor(os, red, green, blue);
return os.str();
};
return ExecuteSuite(MakeTestSuite("CPPUtils::ForegroundTrueColor(uint8_t, uint8_t, uint8_t)",
function_to_test,
{
MakeTest("should write \"\\033[38;2;21;69;136m\"",
(string) "\033[38;2;21;69;136m",
make_tuple(0x15, 0x45, 0x88)),
}));
}
TestResults test_BackgroundTrueColorWith3UInt8() {
auto function_to_test = [](uint8_t red, uint8_t green, uint8_t blue) {
ostringstream os;
CPPUtils::BackgroundTrueColor(os, red, green, blue);
return os.str();
};
return ExecuteSuite(MakeTestSuite("CPPUtils::BackgroundTrueColor(uint8_t, uint8_t, uint8_t)",
function_to_test,
{
MakeTest("should write \"\\033[48;2;21;69;136m\"",
(string) "\033[48;2;21;69;136m",
make_tuple(0x15, 0x45, 0x88)),
}));
}
TestResults test_Reset() {
auto function_to_test = []() {
ostringstream os;
CPPUtils::Reset(os);
return os.str();
};
return ExecuteSuite(MakeTestSuite("CPPUtils::Reset",
function_to_test,
{
MakeTest("should write \"\\033[m\"", (string) "\033[m", make_tuple()),
}));
}
int main(int argc, char *argv[]) {
TestResults results;
results += test_GetRedComponent();
results += test_GetGreenComponent();
results += test_GetBlueComponent();
results += test_EscapeWithBasicString();
results += test_EscapeWithBasicStringView();
results += test_EscapeWithConstCharStar();
results += test_ForegroundColor8Bit();
results += test_BackgroundColor8Bit();
results += test_ForegroundTrueColorWithUInt32();
results += test_BackgroundTrueColorWithUInt32();
results += test_ForegroundTrueColorWith3UInt8();
results += test_BackgroundTrueColorWith3UInt8();
results += test_Reset();
return results.Failed() + results.Errors();
}

View File

@@ -0,0 +1,201 @@
/**********************************************************************************************************************
* *
* @file console_logger_test.cpp *
* *
* @brief Defines tests for the ConsoleLogger class that is a logging destination for the Logger class declared in *
* logger.h. *
* @copyright Copyright (C) 2023 by Tom Hicks <headhunter3@gmail.com> *
* *
* Licensed under the MIT license see below for details. *
* *
* MIT License *
* *
* Copyright (c) 2023 Tom Hicks <headhunter3@gmail.com> *
* *
* 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. *
* *
**********************************************************************************************************************/
#include "console_logger.h"
#include <iostream>
#include <sstream>
#include <tuple>
#include "logger.h"
#include "tinytest.h"
namespace {
using CPPUtils::ConsoleLogger;
using CPPUtils::Logger;
using std::cout;
using std::make_shared;
using std::make_tuple;
using std::ostream;
using std::ostringstream;
using std::string;
using TinyTest::ExecuteSuite;
using TinyTest::MakeTest;
using TinyTest::MakeTestSuite;
using TinyTest::TestResults;
string no_errors = "no errors";
} // namespace
TestResults test_ConsoleLogger_LogMessage() {
auto log_message = [](const Logger::MessageType &type, const string &message) -> string {
ostringstream errors;
ostringstream output;
auto destination = make_shared<ConsoleLogger>();
destination->SetOutputStream(output);
destination->LogMessage(type, message);
return output.str();
};
return ExecuteSuite(MakeTestSuite("CPPUtils::ConsoleLogger::LogMessage(cosnt std::string&)",
log_message,
{MakeTest("should print \"[Debug] this is a message\"",
(string) "[Debug] this is a message\n",
make_tuple(Logger::MessageType::Debug, "this is a message")),
MakeTest("should print \"[Error] this is an error\"",
(string) "[Error] this is an error\n",
make_tuple(Logger::MessageType::Error, "this is an error")),
MakeTest("should print \"[Wtf] what a terrible failure\"",
(string) "[Wtf] what a terrible failure\n",
make_tuple(Logger::MessageType::Wtf, "what a terrible failure")),
MakeTest("should print \"[Info] this is some information\"",
(string) "[Info] this is some information\n",
make_tuple(Logger::MessageType::Info, "this is some information")),
MakeTest("should print \"[Warning] this is a warning\"",
(string) "[Warning] this is a warning\n",
make_tuple(Logger::MessageType::Warning, "this is a warning")),
MakeTest("should print \"[Verbose] this is verbose\"",
(string) "[Verbose] this is verbose\n",
make_tuple(Logger::MessageType::Verbose, "this is verbose")),
MakeTest("should print \"[Unclassified] unclassified message\"",
(string) "[Unclassified] unclassified message\n",
make_tuple((Logger::MessageType)1000, "unclassified message"))}));
}
TestResults test_ConsoleLogger_LogErrorWithMessage() {
auto log_error = [](const Logger::MessageType &type, const std::exception &ex) -> string {
ostringstream errors;
ostringstream output;
auto destination = make_shared<ConsoleLogger>();
destination->SetOutputStream(output);
destination->LogError(type, ex);
return output.str();
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::ConsoleLogger::LogError(const std::exception&)",
log_error,
{MakeTest("should print \"[Debug] caught exception: this is an exception\"",
(string) "[Debug] caught exception: this is an exception\n",
make_tuple(Logger::MessageType::Debug, std::runtime_error("this is an exception"))),
MakeTest("should print \"[Error] caught exception: this is an error\"",
(string) "[Error] caught exception: this is an error\n",
make_tuple(Logger::MessageType::Error, std::runtime_error("this is an error"))),
MakeTest("should print \"[Wtf] caught exception: what a terrible failure\"",
(string) "[Wtf] caught exception: what a terrible failure\n",
make_tuple(Logger::MessageType::Wtf, std::runtime_error("what a terrible failure"))),
MakeTest("should print \"[Info] caught exception: this is some information\"",
(string) "[Info] caught exception: this is some information\n",
make_tuple(Logger::MessageType::Info, std::runtime_error("this is some information"))),
MakeTest("should print \"[Warning] caught exception: this is a warning\"",
(string) "[Warning] caught exception: this is a warning\n",
make_tuple(Logger::MessageType::Warning, std::runtime_error("this is a warning"))),
MakeTest("should print \"[Verbose] caught exception: this is verbose\"",
(string) "[Verbose] caught exception: this is verbose\n",
make_tuple(Logger::MessageType::Verbose, std::runtime_error("this is verbose"))),
MakeTest("should print \"[Unclassified] caught exception: unclassified message\"",
(string) "[Unclassified] caught exception: unclassified message\n",
make_tuple((Logger::MessageType)1000, std::runtime_error("unclassified message")))}));
}
TestResults test_ConsoleLogger_LogErrorWithoutMessage() {
auto log_error = [](const Logger::MessageType &type, const std::string &message, const std::exception &ex) -> string {
ostringstream errors;
ostringstream output;
auto destination = make_shared<ConsoleLogger>();
destination->SetOutputStream(output);
destination->LogError(type, message, ex);
return output.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::ConsoleLogger::LogError(const std::string&, const std::exception&)",
log_error,
{
MakeTest(
"should print \"[Debug] this is a message with caught exception this is an exception\"",
(string) "[Debug] this is a message with caught exception this is an exception\n",
make_tuple(Logger::MessageType::Debug, "this is a message", std::runtime_error("this is an exception"))),
MakeTest(
"should print \"[Error] this is an error with caught exception this is an exception\"",
(string) "[Error] this is an error with caught exception this is an exception\n",
make_tuple(Logger::MessageType::Error, "this is an error", std::runtime_error("this is an exception"))),
MakeTest("should print \"[Wtf] what a terrible failure with caught exception this is an exception\"",
(string) "[Wtf] what a terrible failure with caught exception this is an exception\n",
make_tuple(Logger::MessageType::Wtf,
"what a terrible failure",
std::runtime_error("this is an exception"))),
MakeTest("should print \"[Info] this is some information with caught exception this is an exception\"",
(string) "[Info] this is some information with caught exception this is an exception\n",
make_tuple(Logger::MessageType::Info,
"this is some information",
std::runtime_error("this is an exception"))),
MakeTest("should print \"[Warning] this is a warning with caught exception this is an exception\"",
(string) "[Warning] this is a warning with caught exception this is an exception\n",
make_tuple(
Logger::MessageType::Warning, "this is a warning", std::runtime_error("this is an exception"))),
MakeTest(
"should print \"[Verbose] this is verbose with caught exception this is an exception\"",
(string) "[Verbose] this is verbose with caught exception this is an exception\n",
make_tuple(Logger::MessageType::Verbose, "this is verbose", std::runtime_error("this is an exception"))),
MakeTest("should print \"[Unclassified] unclassified message with caught exception this is an exception\"",
(string) "[Unclassified] unclassified message with caught exception this is an exception\n",
make_tuple(
(Logger::MessageType)1000, "unclassified message", std::runtime_error("this is an exception"))),
}));
}
TestResults test_ConsoleLogger_SetOutputStream() {
auto set_get_output_stream = [](std::ostream &os, bool only_get) -> bool {
auto destination = make_shared<ConsoleLogger>();
if (!only_get) {
destination->SetOutputStream(os);
}
return &destination->GetOutputStream() == &os;
};
std::ostringstream os1;
return ExecuteSuite(MakeTestSuite(
"CPPUtils::ConsoleLogger::Set/GetOutputStream(std::ostream&)",
set_get_output_stream,
{
MakeTest("should get cout by default", true, make_tuple(std::ref(std::cout), true)),
MakeTest("should set and get the same output stream", true, make_tuple(std::ref(std::cout), false)),
MakeTest("should set and get the same output stream", true, make_tuple(std::ref((std::ostream &)os1), false)),
}));
}
int main(int argc, char *argv[]) {
TestResults results;
results += test_ConsoleLogger_LogMessage();
results += test_ConsoleLogger_LogErrorWithMessage();
results += test_ConsoleLogger_LogErrorWithoutMessage();
results += test_ConsoleLogger_SetOutputStream();
PrintResults(cout, results);
return results.Failed() + results.Errors();
}

806
tests/logger_test.cpp Normal file
View File

@@ -0,0 +1,806 @@
/**********************************************************************************************************************
* *
* @file logger_test.h *
* *
* @brief Defines tests for the Logger class declared in logger.h. *
* @copyright Copyright (C) 2023 by Tom Hicks <headhunter3@gmail.com> *
* *
* Licensed under the MIT license see below for details. *
* *
* MIT License *
* *
* Copyright (c) 2023 Tom Hicks <headhunter3@gmail.com> *
* *
* 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. *
* *
**********************************************************************************************************************/
#include "logger.h"
#include <iostream>
#include <memory>
#include <optional>
#include <sstream>
#include <stdexcept>
#include <string>
#include <tuple>
#include <vector>
#include "tinytest.h"
namespace {
using CPPUtils::Logger;
using std::cout;
using std::endl;
using std::get;
using std::make_optional;
using std::make_shared;
using std::make_tuple;
using std::nullopt;
using std::optional;
using std::ostream;
using std::ostringstream;
using std::runtime_error;
using std::shared_ptr;
using std::string;
using std::tuple;
using std::vector;
using TinyTest::ExecuteSuite;
using TinyTest::MakeTest;
using TinyTest::MakeTestSuite;
using TinyTest::TestResults;
string no_errors = "no errors";
typedef tuple<Logger::MessageType, optional<string>, optional<string>> LogEntry;
class SpyLoggerDestination : public Logger::Destination {
public:
SpyLoggerDestination() {
min_type_ = Logger::MessageType::Unknown;
max_type_ = Logger::MessageType::Wtf;
}
virtual ~SpyLoggerDestination() {}
virtual void LogMessage(const Logger::MessageType &type, const std::string &message) const {
log.push_back(make_tuple(type, message, nullopt));
}
virtual void LogError(const Logger::MessageType &type, const std::exception &ex) const {
log.push_back(make_tuple(type, nullopt, ex.what()));
}
virtual void LogError(const Logger::MessageType &type, const std::string &message, const std::exception &ex) const {
log.push_back(make_tuple(type, message, ex.what()));
}
mutable vector<LogEntry> log;
};
template <typename T> ostream &PrintOptional(ostream &os, optional<T> op) {
if (op.has_value()) {
os << op.value();
} else {
os << "nullopt";
}
return os;
}
void ExpectMessageType(ostream &error_message, const Logger::MessageType &expected, const LogEntry &log_entry) {
Logger::MessageType actual = get<0>(log_entry);
if (actual != expected) {
error_message << "Unexpected MessageType expected: " << expected << ", actual: " << actual << endl;
}
}
void ExpectMessageText(ostream &error_message, optional<string> expected, const LogEntry &log_entry) {
optional<string> actual = get<1>(log_entry);
if (actual != expected) {
error_message << "Unexpected message text. Expected: ";
PrintOptional(error_message, expected) << ", Actual: ";
PrintOptional(error_message, actual) << endl;
}
}
void ExpectMessageException(ostream &error_message, optional<string> expected, const LogEntry &log_entry) {
optional<string> actual = get<2>(log_entry);
if (actual != expected) {
error_message << "Unexpected message exception. Expected: ";
PrintOptional(error_message, expected) << ", Actual: ";
PrintOptional(error_message, actual) << endl;
}
}
void ExpectLogSize(ostream &error_message, size_t expected, shared_ptr<SpyLoggerDestination> destination) {
size_t actual = destination->log.size();
if (actual != expected) {
error_message << "Unexpected number of events logged. Expected: " << expected << ", Actual: " << actual << endl;
}
}
string GetError(ostringstream &error_message) {
string error = error_message.str();
if (error.size() > 0) {
return error;
}
return no_errors;
}
} // End namespace
TestResults test_Destination_TypeRangeGettersAndSetters() {
TestResults results;
auto set_min_type = [](const Logger::MessageType &type) {
auto spy = make_shared<SpyLoggerDestination>();
if (type == Logger::MessageType::Unknown) {
spy->SetMinType(Logger::MessageType::Debug);
} else {
spy->SetMinType(Logger::MessageType::Unknown);
}
spy->SetMinType(type);
return spy->GetMinType();
};
results += ExecuteSuite(MakeTestSuite(
"CPPUtils::Logger::SetMinType(const MessageType&)",
set_min_type,
{
MakeTest(
"should set min type to Unknown", Logger::MessageType::Unknown, make_tuple(Logger::MessageType::Unknown)),
MakeTest("should set min type to Debug", Logger::MessageType::Debug, make_tuple(Logger::MessageType::Debug)),
MakeTest(
"should set min type to Verbose", Logger::MessageType::Verbose, make_tuple(Logger::MessageType::Verbose)),
MakeTest("should set min type to Info", Logger::MessageType::Info, make_tuple(Logger::MessageType::Info)),
MakeTest(
"should set min type to Warning", Logger::MessageType::Warning, make_tuple(Logger::MessageType::Warning)),
MakeTest("should set min type to Error", Logger::MessageType::Error, make_tuple(Logger::MessageType::Error)),
MakeTest("should set min type to Wtf", Logger::MessageType::Wtf, make_tuple(Logger::MessageType::Wtf)),
MakeTest("should set min type to Unknown for an invalid MessageType",
Logger::MessageType::Unknown,
(make_tuple((Logger::MessageType)-1))),
}));
auto set_max_type = [](const Logger::MessageType &type) {
auto spy = make_shared<SpyLoggerDestination>();
if (type == Logger::MessageType::Unknown) {
spy->SetMaxType(Logger::MessageType::Debug);
} else {
spy->SetMaxType(Logger::MessageType::Unknown);
}
spy->SetMaxType(type);
return spy->GetMaxType();
};
results += ExecuteSuite(MakeTestSuite(
"CPPUtils::Logger::SetMaxType(const MessageType&)",
set_max_type,
{
MakeTest(
"should set max type to Unknown", Logger::MessageType::Unknown, make_tuple(Logger::MessageType::Unknown)),
MakeTest("should set max type to Debug", Logger::MessageType::Debug, make_tuple(Logger::MessageType::Debug)),
MakeTest(
"should set max type to Verbose", Logger::MessageType::Verbose, make_tuple(Logger::MessageType::Verbose)),
MakeTest("should set max type to Info", Logger::MessageType::Info, make_tuple(Logger::MessageType::Info)),
MakeTest(
"should set max type to Warning", Logger::MessageType::Warning, make_tuple(Logger::MessageType::Warning)),
MakeTest("should set max type to Error", Logger::MessageType::Error, make_tuple(Logger::MessageType::Error)),
MakeTest("should set max type to Wtf", Logger::MessageType::Wtf, make_tuple(Logger::MessageType::Wtf)),
MakeTest("should set max type to Unknown for an invalid MessageType",
Logger::MessageType::Unknown,
(make_tuple((Logger::MessageType)-1))),
}));
return results;
}
TestResults test_Logger_GetShared() {
auto function_to_test = []() {
auto first = Logger::GetShared();
auto second = Logger::GetShared();
return first == second;
};
return ExecuteSuite(MakeTestSuite("CPPUtils::Logger::GetShared()",
function_to_test,
{
MakeTest("should get the same instance twice", true, make_tuple()),
}));
}
TestResults test_Logger_GetUnique() {
auto get_unique_is_different = []() {
auto first = Logger::GetUnique();
auto second = Logger::GetUnique();
return first != second;
};
auto get_unique_is_not_get_shared = []() {
auto shared = Logger::GetShared();
auto unique = Logger::GetUnique();
return unique != shared;
};
TestResults results;
results += ExecuteSuite(MakeTestSuite("CPPUtils::Logger::GetUnique()",
get_unique_is_different,
{
MakeTest("should get two different instances", true, make_tuple()),
}));
results += ExecuteSuite(
MakeTestSuite("CPPUtils::Logger::GetUnique()",
get_unique_is_not_get_shared,
{
MakeTest("should get and instance that is not the shared instance", true, make_tuple()),
}));
return results;
}
TestResults test_LogUnimplementedMethod() {
#if __cplusplus >= 202002L
return TestResults().fail("Not implemented for c++20 yet.");
ostringstream error_message;
error_message << "Unimplemented method: \"" << location.function_name() << "\" at " << location.file_name() << " ("
<< location.line() << ":" << location.column() << ")";
LogDebug(error_message.str());
// TODO: see what this results in when run in c++20 and test for those values.
#else
auto function_to_test = [](string method_name) -> string {
auto spy = make_shared<SpyLoggerDestination>();
auto logger = Logger::GetUnique();
logger->AddDestination(spy);
#if __cplusplus >= 202002L
std::source_location loc;
logger->LogUnimplementedMethod()
#else
logger->LogUnimplementedMethodReal(method_name);
#endif
ostringstream error_message;
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, Logger::MessageType::Debug, message);
ExpectMessageText(error_message, "Unimplemented method: int main(int argc, char* argv[])", message);
ExpectMessageException(error_message, nullopt, message);
}
return GetError(error_message);
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::Logger::LogUnimplementedMethod",
function_to_test,
{
MakeTest("should log a debug message", no_errors, make_tuple("int main(int argc, char* argv[])")),
}));
#endif
}
TestResults test_Logger_LogUnhandledError() {
auto log_unhandled_error = []() {
auto logger = Logger::GetUnique();
auto spy = make_shared<SpyLoggerDestination>();
logger->AddDestination(spy);
std::exception ex;
logger->LogUnhandledError(ex);
ostringstream error_message;
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, Logger::MessageType::Debug, message);
ExpectMessageText(error_message, "Unhandled exception", message);
ExpectMessageException(error_message, ex.what(), message);
}
return GetError(error_message);
};
return ExecuteSuite(MakeTestSuite("CPPUtils::Logger::LogUnhandledError(const std::exception&)",
log_unhandled_error,
{
MakeTest("should log an error", no_errors, make_tuple()),
}));
}
TestResults test_Logger_LogUnimplementedFeature() {
auto log_unimplemented_feature = []() {
auto logger = Logger::GetUnique();
auto spy = make_shared<SpyLoggerDestination>();
logger->AddDestination(spy);
string feature_name = "rolling over";
logger->LogUnimplementedFeature(feature_name);
ostringstream error_message;
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, Logger::MessageType::Debug, message);
ExpectMessageText(error_message, "Unimplemented feature: " + feature_name, message);
ExpectMessageException(error_message, nullopt, message);
}
return GetError(error_message);
};
return ExecuteSuite(MakeTestSuite("CPPUtils::Logger::LogUnimplementedFeature()",
log_unimplemented_feature,
{
MakeTest("should log an unimplemented feature", no_errors, make_tuple()),
}));
}
TestResults test_Logger_Log_Level() {
auto log = [](const Logger::MessageType &type,
const optional<string> &message_text,
const optional<std::exception> &ex) -> string {
ostringstream error_message;
auto logger = Logger::GetUnique();
auto spy = make_shared<SpyLoggerDestination>();
logger->AddDestination(spy);
switch (type) {
case Logger::MessageType::Debug:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->LogDebug(message_text.value(), ex.value());
} else {
logger->LogDebug(message_text.value());
}
} else {
if (ex.has_value()) {
logger->LogDebug(ex.value());
}
}
break;
case Logger::MessageType::Verbose:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->LogVerbose(message_text.value(), ex.value());
} else {
logger->LogVerbose(message_text.value());
}
} else {
if (ex.has_value()) {
logger->LogVerbose(ex.value());
}
}
break;
case Logger::MessageType::Info:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->LogInfo(message_text.value(), ex.value());
} else {
logger->LogInfo(message_text.value());
}
} else {
if (ex.has_value()) {
logger->LogInfo(ex.value());
}
}
break;
case Logger::MessageType::Warning:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->LogWarning(message_text.value(), ex.value());
} else {
logger->LogWarning(message_text.value());
}
} else {
if (ex.has_value()) {
logger->LogWarning(ex.value());
}
}
break;
case Logger::MessageType::Error:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->LogError(message_text.value(), ex.value());
} else {
logger->LogError(message_text.value());
}
} else {
if (ex.has_value()) {
logger->LogError(ex.value());
}
}
break;
case Logger::MessageType::Wtf:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->LogWtf(message_text.value(), ex.value());
} else {
logger->LogWtf(message_text.value());
}
} else {
if (ex.has_value()) {
logger->LogWtf(ex.value());
}
}
break;
default:
break;
}
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, type, message);
ExpectMessageText(error_message, message_text, message);
ExpectMessageException(error_message, ex.has_value() ? make_optional(ex.value().what()) : nullopt, message);
}
return GetError(error_message);
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::Logger::Log*(...)",
log,
{
MakeTest("should log what a terrible failure with a message",
no_errors,
make_tuple(Logger::MessageType::Wtf,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log what a terrible failure with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Wtf,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log what a terrible failure with a message",
no_errors,
make_tuple(Logger::MessageType::Wtf,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an error with a message",
no_errors,
make_tuple(Logger::MessageType::Error,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log an error with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Error,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an error with a message",
no_errors,
make_tuple(Logger::MessageType::Error,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a warning with a message",
no_errors,
make_tuple(Logger::MessageType::Warning,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log a warning with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Warning,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a warning with a message",
no_errors,
make_tuple(Logger::MessageType::Warning,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an info with a message",
no_errors,
make_tuple(Logger::MessageType::Info,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log an info with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Info,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an info with a message",
no_errors,
make_tuple(Logger::MessageType::Info,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a debug with a message",
no_errors,
make_tuple(Logger::MessageType::Debug,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log a debug with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Debug,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a debug with a message",
no_errors,
make_tuple(Logger::MessageType::Debug,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a verbose with a message",
no_errors,
make_tuple(Logger::MessageType::Verbose,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log a verbose with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Verbose,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a verbose with a message",
no_errors,
make_tuple(Logger::MessageType::Verbose,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
}));
}
TestResults test_Logger_Log() {
auto log = [](const Logger::MessageType &type,
const optional<string> &message_text,
const optional<std::exception> &ex) -> string {
ostringstream error_message;
auto logger = Logger::GetUnique();
auto spy = make_shared<SpyLoggerDestination>();
logger->AddDestination(spy);
switch (type) {
case Logger::MessageType::Debug:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Debug, message_text.value(), ex.value());
} else {
logger->Log(Logger::MessageType::Debug, message_text.value());
}
} else {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Debug, ex.value());
}
}
break;
case Logger::MessageType::Verbose:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Verbose, message_text.value(), ex.value());
} else {
logger->Log(Logger::MessageType::Verbose, message_text.value());
}
} else {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Verbose, ex.value());
}
}
break;
case Logger::MessageType::Info:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Info, message_text.value(), ex.value());
} else {
logger->Log(Logger::MessageType::Info, message_text.value());
}
} else {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Info, ex.value());
}
}
break;
case Logger::MessageType::Warning:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Warning, message_text.value(), ex.value());
} else {
logger->Log(Logger::MessageType::Warning, message_text.value());
}
} else {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Warning, ex.value());
}
}
break;
case Logger::MessageType::Error:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Error, message_text.value(), ex.value());
} else {
logger->Log(Logger::MessageType::Error, message_text.value());
}
} else {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Error, ex.value());
}
}
break;
case Logger::MessageType::Wtf:
if (message_text.has_value()) {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Wtf, message_text.value(), ex.value());
} else {
logger->Log(Logger::MessageType::Wtf, message_text.value());
}
} else {
if (ex.has_value()) {
logger->Log(Logger::MessageType::Wtf, ex.value());
}
}
break;
default:
break;
}
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, type, message);
ExpectMessageText(error_message, message_text, message);
ExpectMessageException(error_message, ex.has_value() ? make_optional(ex.value().what()) : nullopt, message);
}
return GetError(error_message);
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::Logger::Log(const MessageType&, ...)",
log,
{
MakeTest("should log what a terrible failure with a message",
no_errors,
make_tuple(Logger::MessageType::Wtf,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log what a terrible failure with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Wtf,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log what a terrible failure with a message",
no_errors,
make_tuple(Logger::MessageType::Wtf,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an error with a message",
no_errors,
make_tuple(Logger::MessageType::Error,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log an error with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Error,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an error with a message",
no_errors,
make_tuple(Logger::MessageType::Error,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a warning with a message",
no_errors,
make_tuple(Logger::MessageType::Warning,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log a warning with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Warning,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a warning with a message",
no_errors,
make_tuple(Logger::MessageType::Warning,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an info with a message",
no_errors,
make_tuple(Logger::MessageType::Info,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log an info with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Info,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log an info with a message",
no_errors,
make_tuple(Logger::MessageType::Info,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a debug with a message",
no_errors,
make_tuple(Logger::MessageType::Debug,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log a debug with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Debug,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a debug with a message",
no_errors,
make_tuple(Logger::MessageType::Debug,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a verbose with a message",
no_errors,
make_tuple(Logger::MessageType::Verbose,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)nullopt)),
MakeTest("should log a verbose with a message and an exception",
no_errors,
make_tuple(Logger::MessageType::Verbose,
(const optional<string> &)"this should never happen",
(const optional<std::exception> &)runtime_error("bad thing happen"))),
MakeTest("should log a verbose with a message",
no_errors,
make_tuple(Logger::MessageType::Verbose,
(const optional<string> &)nullopt,
(const optional<std::exception> &)runtime_error("bad thing happen"))),
}));
}
TestResults test_Logger_LogToDo() {
auto log_to_do = [](const string &todo_message) {
auto logger = Logger::GetUnique();
auto spy = make_shared<SpyLoggerDestination>();
logger->AddDestination(spy);
logger->LogToDo(todo_message);
ostringstream error_message;
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, Logger::MessageType::Debug, message);
ExpectMessageText(error_message, "TODO: " + todo_message, message);
ExpectMessageException(error_message, nullopt, message);
}
return GetError(error_message);
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::Logger::LogToDo(const std:;string&)",
log_to_do,
{
MakeTest("should log a TODO for \"fill in this function\"", no_errors, make_tuple("fill in this function")),
MakeTest("should log a TODO for \"delete this after fixing bug:2048\"",
no_errors,
make_tuple("delete this after fixing bug:2048")),
MakeTest("should log a TODO for \"refactor this\"", no_errors, make_tuple("refactor this")),
}));
}
TestResults test_Logger_AddDestination_and_ClearDestinations() {
auto add_destination = []() {
ostringstream error_message;
auto logger = Logger::GetUnique();
auto spy = make_shared<SpyLoggerDestination>();
ExpectLogSize(error_message, 0, spy);
logger->LogInfo("first message");
ExpectLogSize(error_message, 0, spy);
logger->AddDestination(spy);
ExpectLogSize(error_message, 0, spy);
logger->LogInfo("second message");
ExpectLogSize(error_message, 1, spy);
logger->ClearDestinations();
ExpectLogSize(error_message, 1, spy);
logger->LogInfo("third message");
ExpectLogSize(error_message, 1, spy);
if (spy->log.size() > 0) {
auto message = spy->log.at(0);
ExpectMessageType(error_message, Logger::MessageType::Info, message);
ExpectMessageText(error_message, "second message", message);
ExpectMessageException(error_message, nullopt, message);
}
return GetError(error_message);
};
return ExecuteSuite(MakeTestSuite("",
add_destination,
{
MakeTest("should add and clear destinations", no_errors, make_tuple()),
}));
}
// AddDestination
// ClearDestinations
int main(int argc, char *argv[]) {
TestResults results;
results += test_Destination_TypeRangeGettersAndSetters();
results += test_Logger_GetShared();
results += test_Logger_GetUnique();
results += test_LogUnimplementedMethod();
results += test_Logger_LogUnhandledError();
results += test_Logger_LogUnimplementedFeature();
results += test_Logger_Log_Level();
results += test_Logger_Log();
results += test_Logger_LogToDo();
results += test_Logger_AddDestination_and_ClearDestinations();
PrintResults(cout, results);
return results.Failed() + results.Errors();
}

447
tests/pretty_print_test.cpp Normal file
View File

@@ -0,0 +1,447 @@
/**********************************************************************************************************************
* *
* @file pretty_print_test.cpp *
* *
* @brief Defines test for the printing functions declared in pretty_print.h. *
* @copyright Copyright (C) 2023 by Tom Hicks <headhunter3@gmail.com> *
* *
* Licensed under the MIT license see below for details. *
* *
* MIT License *
* *
* Copyright (c) 2023 Tom Hicks <headhunter3@gmail.com> *
* *
* 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. *
* *
**********************************************************************************************************************/
// clang-format off
#include "pretty_print.h"
#include "tinytest.h"
// clang-format on
#include <deque>
#include <functional>
#include <initializer_list>
#include <queue>
#include <sstream>
#include <string>
#include <tuple>
#include <utility>
namespace {
using std::make_tuple;
using std::ostringstream;
using std::string;
using std::string_view;
using TinyTest::ExecuteSuite;
using TinyTest::MakeTest;
using TinyTest::MakeTestSuite;
using TinyTest::TestResults;
using namespace CPPUtils;
using std::wstring;
} // End namespace
TestResults test_EscapeForPrintingWithAConstCharPointer() {
TestResults results;
auto escape_const_char_pointer = [](const char *value) -> string { return EscapeForPrinting(value); };
results += ExecuteSuite(
MakeTestSuite("CPPUtils::EscapeForPrinting(const char*)",
escape_const_char_pointer,
{
MakeTest("should escape an empty string", (string) "", make_tuple("")),
MakeTest("should esacpe a string with no special characters",
(string) "This is a normal string.",
make_tuple("This is a normal string.")),
MakeTest("should escape the escape character by itself", (string) "\\033", make_tuple("\033")),
MakeTest("should escape the escape character within a string",
(string) "This string has an \\033 in it.",
make_tuple("This string has an \033 in it.")),
}));
return results;
}
TestResults test_EscapeForPrintingWithAString() {
TestResults results;
auto escape_string = [](const string &value) -> string { return EscapeForPrinting(value); };
results += ExecuteSuite(MakeTestSuite(
"CPPUtils::EscapeForPrinting(const std::string&)",
escape_string,
{
MakeTest("should escape an empty string", (string) "", make_tuple((string) "")),
MakeTest("should escape a string with no special characters",
(string) "This is a normal string.",
make_tuple((string) "This is a normal string.")),
MakeTest("should escape the escape character by itself", (string) "\\033", make_tuple((string) "\033")),
MakeTest("should escape the escape character within a string",
(string) "This string has an \\033 in it.",
make_tuple((string) "This string has an \033 in it.")),
}));
return results;
}
TestResults test_EscapeForPrintingWithAStringView() {
auto escape_string_view = [](const string_view &value) -> string { return EscapeForPrinting(value); };
return ExecuteSuite(MakeTestSuite(
"CPPUtils::EscapeForPrinting(const std::string_view&)",
escape_string_view,
{
MakeTest("should escape an empty string", (string) "", make_tuple((string_view) "")),
MakeTest("should escape a string with no special characters",
(string) "This is a normal string.",
make_tuple((string_view) "This is a normal string.")),
MakeTest("should escape the escape character by itself", (string) "\\033", make_tuple((string_view) "\033")),
MakeTest("should escape the escape character within a string",
(string) "This string has an \\033 in it.",
make_tuple((string_view) "This string has an \033 in it.")),
}));
}
TestResults test_PrettyPrintWithAConstCharPointer() {
auto pretty_print = [](const char *value) -> string {
ostringstream os;
PrettyPrint(os, value);
return os.str();
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::PrettyPrint(std::ostream&, const char*)",
pretty_print,
{
MakeTest("should print \"\" for an empty string", (string) "\"\"", make_tuple("")),
MakeTest("should print \"hello world\"", (string) "\"hello world\"", make_tuple("hello world")),
}));
}
TestResults test_PrettyPrintWithAString() {
auto pretty_print = [](const string &value) -> string {
ostringstream os;
PrettyPrint(os, value);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrint(std::ostream&, const std::string&)",
pretty_print,
{
MakeTest("should print \"\" for an empty string", (string) "\"\"", make_tuple((string) "")),
MakeTest("should print \"hello world\"", (string) "\"hello world\"", make_tuple((string) "hello world")),
}));
}
TestResults test_PrettyPrintWithAStringView() {
auto pretty_print = [](const std::string_view &value) -> string {
ostringstream os;
PrettyPrint(os, value);
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrint(std::ostream&, const std::string_view&)",
pretty_print,
{
MakeTest("should print \"\" for an empty string", (string) "\"\"", make_tuple((string_view) "")),
MakeTest("should print \"hello world\"", (string) "\"hello world\"", make_tuple((string_view) "hello world")),
}));
}
TestResults test_PrettyPrintWithATuple() {
auto pretty_print = [](int i) -> string {
ostringstream os;
switch (i) {
case 1:
PrettyPrint(os, make_tuple(1, "hello", 9));
break;
case 2:
PrettyPrint(os, make_tuple());
break;
case 3:
PrettyPrint(os, make_tuple("one", "two", "three"));
break;
}
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrint(std::ostream&, std::tuple)",
pretty_print,
{
MakeTest("should print a tuple of mixed types", (string) "[ 1, \"hello\", 9 ]", make_tuple(1)),
MakeTest("should print an empty tuple", (string) "[]", make_tuple(2)),
MakeTest("should print a tuple of strings", (string) "[ \"one\", \"two\", \"three\" ]", make_tuple(3)),
}));
}
TestResults test_PrettyPrintWithAnInitializerList() {
auto pretty_print = [](int i) {
ostringstream os;
std::initializer_list<string> empty_initializer_list = {};
switch (i) {
case 1:
PrettyPrint(os, {"one", "two", "three"});
break;
case 2:
PrettyPrint(os, empty_initializer_list);
break;
case 3:
PrettyPrint(os, {1, 2, 3});
break;
case 4:
PrettyPrint(os, {"one", "two", "three", "four"});
break;
case 5:
PrettyPrint(os, {1.1, 2.2, 3.3});
break;
}
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrint(std::ostream&, std::initializer_list)",
pretty_print,
{
MakeTest(
"should print an initializer_list of strings", (string) "[ \"one\", \"two\", \"three\" ]", make_tuple(1)),
MakeTest("should print an empty initializer_list", (string) "[]", make_tuple(2)),
MakeTest("should print an initializer_list of integers", (string) "[ 1, 2, 3 ]", make_tuple(3)),
MakeTest("should print an initializer_list of strings with four elements",
(string) "[ \"one\", \"two\", \"three\", \"four\" ]",
make_tuple(4)),
MakeTest("should print an initializer_list of doubles", (string) "[ 1.1, 2.2, 3.3 ]", make_tuple(5)),
}));
}
TestResults test_PrettyPrintWithDifferentContainerTypes() {
auto pretty_print = [](int i) {
ostringstream os;
switch (i) {
case 1: {
std::vector<int> v = {1, 2, 3};
PrettyPrint(os, v);
break;
}
case 2: {
std::queue<int> q;
q.push(1);
q.push(2);
q.push(3);
PrettyPrint(os, q);
break;
}
case 3: {
std::vector<string> v = {"one", "two", "three"};
PrettyPrint(os, v);
break;
}
case 4: {
std::queue<string> q;
q.push("one");
q.push("two");
q.push("three");
PrettyPrint(os, q);
break;
}
}
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrint(std::ostream&, TContainer)",
pretty_print,
{
MakeTest("should print a vector of integers", (string) "[ 1, 2, 3 ]", make_tuple(1)),
MakeTest("should print a queue of integers", (string) "[ 1, 2, 3 ]", make_tuple(2)),
MakeTest("should print a vector of strings", (string) "[ \"one\", \"two\", \"three\" ]", make_tuple(3)),
MakeTest("should print a queue of strings", (string) "[ \"one\", \"two\", \"three\" ]", make_tuple(4)),
}));
}
TestResults test_PrettyPrintWithSimpleTypes() {
TestResults results;
auto pretty_print_int = [](int value) -> string {
ostringstream os;
PrettyPrint(os, value);
return os.str();
};
results += ExecuteSuite(MakeTestSuite("CPPUtils::PrettyPrint(std::ostream&, const TItem&)",
pretty_print_int,
{
MakeTest("should print 42 for an int", (string) "42", make_tuple(42)),
}));
auto pretty_print_float = [](float value) -> string {
ostringstream os;
PrettyPrint(os, value);
return os.str();
};
results +=
ExecuteSuite(MakeTestSuite("CPPUtils::PrettyPrint(std::ostream&, const TItem&)",
pretty_print_float,
{
MakeTest("should print 3.14 for a float", (string) "3.14", make_tuple(3.14f)),
}));
auto pretty_print_string = [](const string &value) -> string {
ostringstream os;
PrettyPrint(os, value);
return os.str();
};
results += ExecuteSuite(MakeTestSuite("CPPUtils::PrettyPrint(std::ostream&, const TItem&)",
pretty_print_string,
{
MakeTest("should print \"hello world\" for a string",
(string) "\"hello world\"",
make_tuple((string) "hello world")),
}));
return results;
}
TestResults test_PrettyPrintWithAPair() {
auto pretty_print = [](int id) -> string {
ostringstream os;
switch (id) {
case 1:
PrettyPrint(os, std::make_pair(1, 2));
break;
case 2:
PrettyPrint(os, std::make_pair(3.14f, 42));
break;
case 3:
PrettyPrint(os, std::make_pair((string) "hello", (string) "world"));
break;
}
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrint(std::ostream&, const std::pair<T1, T2>&)",
pretty_print,
{
MakeTest("should print (1, 2) for a pair of ints", (string) "(1, 2)", make_tuple(1)),
MakeTest("should print (3.14, 42) for a pair of float and int", (string) "(3.14, 42)", make_tuple(2)),
MakeTest("should print (\"hello\", \"world\") for a pair of strings",
(string) "(\"hello\", \"world\")",
make_tuple(3)),
}));
}
TestResults test_PrettyPrintWithSeparatorWithAConstCharPointer() {
auto pretty_print = [](const char *separator, int id) -> string {
ostringstream os;
switch (id) {
case 1:
PrettyPrintWithSeparator(os, separator, 1, 2, 3);
break;
case 2:
PrettyPrintWithSeparator(os, separator, 3.14f, 42, (string) "hello world");
break;
case 3:
PrettyPrintWithSeparator(os, separator, (string) "hello", (string) "world");
break;
}
return os.str();
};
return ExecuteSuite(
MakeTestSuite("CPPUtils::PrettyPrintWithSeparator(std::ostream&, const TChar*, Args&&...)",
pretty_print,
{
MakeTest("should print 1, 2, 3 for a list of ints", (string) "1, 2, 3", make_tuple(", ", 1)),
MakeTest("should print 3.14; 42; \"hello world\" for a list of float, int and string",
(string) "3.14; 42; \"hello world\"",
make_tuple("; ", 2)),
MakeTest("should print \"hello\" \"world\" for a list of strings",
(string) "\"hello\" \"world\"",
make_tuple(" ", 3)),
}));
}
TestResults test_PrettyPrintWithSeparatorWithAString() {
auto pretty_print = [](const string &separator, int id) -> string {
ostringstream os;
switch (id) {
case 1:
PrettyPrintWithSeparator(os, separator, 1, 2, 3);
break;
case 2:
PrettyPrintWithSeparator(os, separator, 3.14f, 42, (string) "hello world");
break;
case 3:
PrettyPrintWithSeparator(os, separator, (string) "hello", (string) "world");
break;
}
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrintWithSeparator(std::ostream&, const TChar*, Args&&...)",
pretty_print,
{
MakeTest("should print 1 | 2 | 3 for a list of ints", (string) "1 | 2 | 3", make_tuple((string) " | ", 1)),
MakeTest("should print 3.14 / 42 / \"hello world\" for a list of float, int and string",
(string) "3.14 / 42 / \"hello world\"",
make_tuple((string) " / ", 2)),
MakeTest("should print \"hello\" - \"world\" for a list of strings",
(string) "\"hello\" - \"world\"",
make_tuple((string) " - ", 3)),
}));
}
TestResults test_PrettyPrintWithSeparatorWithAStringView() {
auto pretty_print = [](const string_view &separator, int id) -> string {
ostringstream os;
switch (id) {
case 1:
PrettyPrintWithSeparator(os, separator, 1, 2, 3);
break;
case 2:
PrettyPrintWithSeparator(os, separator, 3.14f, 42, "hello world");
break;
case 3:
PrettyPrintWithSeparator(os, separator, "hello", "world");
break;
}
return os.str();
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::PrettyPrintWithSeparator(std::ostream&, const TChar*, Args&&...)",
pretty_print,
{
MakeTest(
"should print 1 | 2 | 3 for a list of ints", (string) "1 | 2 | 3", make_tuple((string_view) " | ", 1)),
MakeTest("should print 3.14 / 42 / \"hello world\" for a list of float, int and string",
(string) "3.14 / 42 / \"hello world\"",
make_tuple((string_view) " / ", 2)),
MakeTest("should print \"hello\" - \"world\" for a list of strings",
(string) "\"hello\" - \"world\"",
make_tuple((string_view) " - ", 3)),
}));
}
int main(int argc, char *argv[]) {
setlocale(LC_ALL, "");
TestResults results;
results += test_EscapeForPrintingWithAConstCharPointer();
results += test_EscapeForPrintingWithAString();
results += test_EscapeForPrintingWithAStringView();
results += test_PrettyPrintWithAConstCharPointer();
results += test_PrettyPrintWithAString();
results += test_PrettyPrintWithAStringView();
results += test_PrettyPrintWithATuple();
results += test_PrettyPrintWithAnInitializerList();
results += test_PrettyPrintWithDifferentContainerTypes();
results += test_PrettyPrintWithSimpleTypes();
results += test_PrettyPrintWithAPair();
results += test_PrettyPrintWithSeparatorWithAConstCharPointer();
results += test_PrettyPrintWithSeparatorWithAString();
results += test_PrettyPrintWithSeparatorWithAStringView();
return results.Failed() + results.Errors();
}

1251
tests/tinytest_test.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,527 @@
/**********************************************************************************************************************
* *
* @file windows_logger_test.cpp *
* *
* @brief Defines tests for the WindowsLogger logging destination class declared in windows_logger.h. *
* This logging destination works with the Logger class declared in logger.h and logs messages by creating a modal *
* windows message box *
* @copyright Copyright (C) 2023 by Tom Hicks <headhunter3@gmail.com> *
* *
* Licensed under the MIT license see below for details. *
* *
* MIT License *
* *
* Copyright (c) 2023 Tom Hicks <headhunter3@gmail.com> *
* *
* 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. *
* *
**********************************************************************************************************************/
#include "windows_logger.h"
#ifdef _WIN32
#include <iostream>
#include <sstream>
#include <tuple>
#include <winuser.h>
#include "logger.h"
#include "tinytest.h"
namespace {
using CPPUtils::Logger;
using CPPUtils::WindowsLogger;
using std::cout;
using std::endl;
using std::get;
using std::hex;
using std::make_shared;
using std::make_tuple;
using std::ostream;
using std::ostringstream;
using std::shared_ptr;
using std::string;
using std::tuple;
using std::vector;
using TinyTest::ExecuteSuite;
using TinyTest::MakeTest;
using TinyTest::MakeTestSuite;
using TinyTest::TestResults;
string no_errors = "no errors";
typedef tuple<string, string, UINT> MessageBoxEvent;
/// @brief
class WindowsLoggerSpy : public WindowsLogger {
public:
/// @brief
mutable vector<MessageBoxEvent> log;
protected:
/// @brief
/// @param body
/// @param title
/// @param u_type
virtual void ShowMessageBox(const string &body, const string &title, UINT u_type) const override {
log.push_back(make_tuple(body, title, u_type));
}
};
/// @brief
/// @param errors
/// @param expected
/// @param spy
void ExpectLogSize(ostream &errors, size_t expected, const shared_ptr<WindowsLoggerSpy> &spy) {
size_t actual = spy->log.size();
if (actual != expected) {
errors << "Log size mismatch. Expected: " << expected << ", Actual: " << actual << endl;
}
}
/// @brief
/// @param errors
/// @param expected
/// @param event
void ExpectMessage(ostream &errors, const string &expected, const MessageBoxEvent &event) {
string actual = get<0>(event);
if (actual != expected) {
errors << "Message mismatch. Expected: " << expected << ", Actual: " << actual << endl;
}
}
/// @brief
/// @param errors
/// @param expected
/// @param event
void ExpectTitle(ostream &errors, const string &expected, const MessageBoxEvent &event) {
string actual = get<1>(event);
if (actual != expected) {
errors << "Title mismatch. Expected: \"" << expected << "\", Actual: \"" << actual << "\"" << endl;
}
}
/// @brief
/// @param parts
/// @param separator
/// @return
string Join(vector<string> parts, const string &separator) {
ostringstream os;
bool first = true;
;
for_each(parts.begin(), parts.end(), [&os, &first, separator](string part) {
if (first) {
first = false;
} else {
os << separator;
}
os << part;
});
return os.str();
}
/// @brief
/// @param u_type
/// @param ignore_defaults
/// @return
string ConvertUTypeToString(UINT u_type, bool ignore_defaults = true) {
UINT u_button = u_type & MB_TYPEMASK;
UINT u_icon = u_type & MB_ICONMASK;
UINT u_default_button = u_type & MB_DEFMASK;
UINT u_mode = u_type & MB_MODEMASK;
UINT u_misc = u_type & MB_MISCMASK;
vector<string> parts;
// MB_OK = 0x00000000L
if (u_button == MB_OK) {
parts.push_back("MB_OK");
}
// MB_OKCANCEL = 0x00000001L
if (u_button == MB_OKCANCEL) {
parts.push_back("MB_OKCANCEL");
}
// MB_ABORTRETRYIGNORE = 0x00000002L
if (u_button == MB_ABORTRETRYIGNORE) {
parts.push_back("MB_ABORTRETRYIGNORE");
}
// MB_YESNOCANCEL = 0x00000003L
if (u_button == MB_YESNOCANCEL) {
parts.push_back("MB_YESNOCANCEL");
}
// MB_YESNO = 0x00000004L
if (u_button == MB_YESNO) {
parts.push_back("MB_YESNO");
}
// MB_RETRYCANCEL = 0x00000005L
if (u_button == MB_RETRYCANCEL) {
parts.push_back("MB_RETRYCANCEL");
}
// MB_CANCELTRYCONTINUE = 0x00000006L
if (u_button == MB_CANCELTRYCONTINUE) {
parts.push_back("MB_CANCELTRYCONTINUE");
}
// MB_ICONHAND = 0x00000010L
if (u_icon == MB_ICONHAND) {
parts.push_back("MB_ICONHAND");
}
// MB_ICONQUESTION = 0x00000020L
if (u_icon == MB_ICONQUESTION) {
parts.push_back("MB_ICONQUESTION");
}
// MB_ICONEXCLAMATION = 0x00000030L
if (u_icon == MB_ICONEXCLAMATION) {
parts.push_back("MB_ICONEXCLAMATION");
}
// MB_ICONASTERISK = 0x00000040L
if (u_icon == MB_ICONASTERISK) {
parts.push_back("MB_ICONASTERISK");
}
// MB_USERICON = 0x00000080L
if (u_icon == MB_USERICON) {
parts.push_back("MB_USERICON");
}
// MB_DEFBUTTON1 = 0x00000000L
if (u_default_button == MB_DEFBUTTON1 && !ignore_defaults) {
parts.push_back("MB_DEFBUTTON1");
}
// MB_DEFBUTTON2 = 0x00000100L
if (u_default_button == MB_DEFBUTTON2) {
parts.push_back("MB_DEFBUTTON2");
}
// MB_DEFBUTTON3 = 0x00000200L
if (u_default_button == MB_DEFBUTTON3) {
parts.push_back("MB_DEFBUTTON3");
}
// MB_DEFBUTTON4 = 0x00000300L
if (u_default_button == MB_DEFBUTTON4) {
parts.push_back("MB_DEFBUTTON4");
}
// MB_APPLMODAL = 0x00000000L
if (u_mode == MB_APPLMODAL && !ignore_defaults) {
parts.push_back("MB_APPLMODAL");
}
// MB_SYSTEMMODAL = 0x00001000L
if (u_mode == MB_SYSTEMMODAL) {
parts.push_back("MB_SYSTEMMODAL");
}
// MB_TASKMODAL = 0x00002000L
if (u_mode == MB_TASKMODAL) {
parts.push_back("MB_TASKMODAL");
}
// MB_HELP = 0x00004000L
if (u_mode == MB_HELP) {
parts.push_back("MB_HELP");
}
// MB_NOFOCUS = 0x00008000L
if (u_mode == MB_NOFOCUS) {
parts.push_back("MB_NOFOCUS");
}
// MB_SETFOREGROUND = 0x00010000L
if (u_misc == MB_SETFOREGROUND) {
parts.push_back("MB_SETFOREGROUND");
}
// MB_DEFAULT_DESKTOP_ONLY = 0x00020000L
if (u_misc == MB_DEFAULT_DESKTOP_ONLY) {
parts.push_back("MB_DEFAULT_DESKTOP_ONLY");
}
// MB_TOPMOST = 0x00040000L
if (u_misc == MB_TOPMOST) {
parts.push_back("MB_TOPMOST");
}
// MB_RIGHT = 0x00080000L
if (u_misc == MB_RIGHT) {
parts.push_back("MB_RIGHT");
}
// MB_RTLREADING = 0x00100000L
if (u_misc == MB_RTLREADING) {
parts.push_back("MB_RTLREADING");
}
// MB_SERVICE_NOTIFICATION = 0x00200000L
// MB_SERVICE_NOTIFICATION = 0x00040000L
if ((u_misc == MB_SERVICE_NOTIFICATION) || (u_misc == MB_SERVICE_NOTIFICATION)) {
parts.push_back("MB_SERVICE_NOTIFICATION");
}
return Join(parts, " | ");
}
/// @brief
/// @param errors
/// @param expected
/// @param event
void ExpectUType(ostream &errors, UINT expected, const MessageBoxEvent &event) {
UINT actual = get<2>(event);
if (actual != expected) {
errors << "u_type mismatch. Expected: " << hex << expected << " (" << ConvertUTypeToString(expected)
<< "), Actual: " << hex << actual << " (" << ConvertUTypeToString(actual) << ")" << endl;
}
}
/// @brief
/// @param error_messages
/// @return
string GetErrors(ostringstream &error_messages) {
string errors = error_messages.str();
if (errors.size() > 0) {
return errors;
}
return no_errors;
}
} // namespace
TestResults test_WindowsLogger_LogMessage() {
auto log_message = [](const Logger::MessageType &type,
const string &message,
const string &body,
const string &title,
UINT u_type) -> string {
ostringstream errors;
auto destination = make_shared<WindowsLoggerSpy>();
destination->LogMessage(type, message);
ExpectLogSize(errors, 1, destination);
if (destination->log.size() > 0) {
auto event = destination->log.at(0);
ExpectMessage(errors, body, event);
ExpectTitle(errors, title, event);
ExpectUType(errors, u_type, event);
}
return GetErrors(errors);
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::WindowsLogger::LogMessage(cosnt std::string&)",
log_message,
{
MakeTest("should log \"this is a message\" with title \"Debug\"",
no_errors,
make_tuple(Logger::MessageType::Debug,
"this is a message",
"this is a message",
"Debug",
MB_OK | MB_ICONEXCLAMATION)),
MakeTest(
"should log \"this is an error\" with title \"ERROR\"",
no_errors,
make_tuple(
Logger::MessageType::Error, "this is an error", "this is an error", "ERROR", MB_OK | MB_ICONHAND)),
MakeTest("should log \"what a terrible failure\" with title \"How did you let this happen?\"",
no_errors,
make_tuple(Logger::MessageType::Wtf,
"what a terrible failure",
"what a terrible failure",
"How did you let this happen?",
MB_OK | MB_ICONHAND)),
MakeTest("should log \"this is some information\" with title \"Information\"",
no_errors,
make_tuple(Logger::MessageType::Info,
"this is some information",
"this is some information",
"Information",
MB_OK | MB_ICONASTERISK)),
MakeTest("should log \"this is a warning\" with title \"Warning\"",
no_errors,
make_tuple(Logger::MessageType::Warning,
"this is a warning",
"this is a warning",
"Warning",
MB_OK | MB_ICONEXCLAMATION)),
MakeTest("should log \"this is verbose\" with title \"Verbose\"",
no_errors,
make_tuple(Logger::MessageType::Verbose,
"this is verbose",
"this is verbose",
"Verbose",
MB_OK | MB_ICONASTERISK)),
MakeTest("should log \"unclassified message\" with title \"Unclassified\"",
no_errors,
make_tuple((Logger::MessageType)1000,
"unclassified message",
"unclassified message",
"Unclassified",
MB_OK | MB_ICONASTERISK)),
}));
}
TestResults test_WindowsLogger_LogErrorWithMessage() {
auto log_error = [](const Logger::MessageType &type,
const std::exception &ex,
const string &expected_body,
const string &expected_title,
UINT expected_utype) -> string {
ostringstream errors;
auto destination = make_shared<WindowsLoggerSpy>();
destination->LogError(type, ex);
ExpectLogSize(errors, 1, destination);
if (destination->log.size() > 0) {
auto event = destination->log.at(0);
ExpectMessage(errors, expected_body, event);
ExpectTitle(errors, expected_title, event);
ExpectUType(errors, expected_utype, event);
}
return GetErrors(errors);
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::WindowsLogger::LogError(const std::exception&)",
log_error,
{
MakeTest("should log \"Exception: this is an exception\" with title \"Debug\"",
no_errors,
make_tuple(Logger::MessageType::Debug,
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"Debug",
MB_OK | MB_ICONEXCLAMATION)),
MakeTest("should log \"Exception: this is an error\" with title \"ERROR\"",
no_errors,
make_tuple(Logger::MessageType::Error,
std::runtime_error("this is an error"),
"Exception: this is an error",
"ERROR",
MB_OK | MB_ICONHAND)),
MakeTest("should log \"Exception: what a terrible failure\" with title \"How did you let this happen?\"",
no_errors,
make_tuple(Logger::MessageType::Wtf,
std::runtime_error("what a terrible failure"),
"Exception: what a terrible failure",
"How did you let this happen?",
MB_OK | MB_ICONHAND)),
MakeTest("should log \"Exception: this is some information\" with title \"Information\"",
no_errors,
make_tuple(Logger::MessageType::Info,
std::runtime_error("this is some information"),
"Exception: this is some information",
"Information",
MB_OK | MB_ICONASTERISK)),
MakeTest("should log \"Exception: this is a warning\" with title \"Warning\"",
no_errors,
make_tuple(Logger::MessageType::Warning,
std::runtime_error("this is a warning"),
"Exception: this is a warning",
"Warning",
MB_OK | MB_ICONEXCLAMATION)),
MakeTest("should log \"Exception: this is verbose\" with title \"Verbose\"",
no_errors,
make_tuple(Logger::MessageType::Verbose,
std::runtime_error("this is verbose"),
"Exception: this is verbose",
"Verbose",
MB_OK | MB_ICONASTERISK)),
MakeTest("should log \"Exception: unclassified message\" with title \"Unclassified\"",
no_errors,
make_tuple((Logger::MessageType)1000,
std::runtime_error("unclassified message"),
"Exception: unclassified message",
"Unclassified",
MB_OK | MB_ICONASTERISK)),
}));
}
TestResults test_WindowsLogger_LogErrorWithoutMessage() {
auto log_error = [](const Logger::MessageType &type,
const std::string &message,
const std::exception &ex,
const string &expected_body,
const string &expected_title,
UINT expected_utype) -> string {
ostringstream errors;
auto destination = make_shared<WindowsLoggerSpy>();
destination->LogError(type, ex);
ExpectLogSize(errors, 1, destination);
if (destination->log.size() > 0) {
auto event = destination->log.at(0);
ExpectMessage(errors, expected_body, event);
ExpectTitle(errors, expected_title, event);
ExpectUType(errors, expected_utype, event);
}
return GetErrors(errors);
};
return ExecuteSuite(MakeTestSuite(
"CPPUtils::WindowsLogger::LogError(const std::string&, const std::exception&)",
log_error,
{
MakeTest("should log \"Exception: this is an exception\" with title \"Debug\"",
no_errors,
make_tuple(Logger::MessageType::Debug,
"this is a message",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"Debug",
MB_OK | MB_ICONEXCLAMATION)),
MakeTest("should log \"Exception: this is an exception\" with title \"ERROR\"",
no_errors,
make_tuple(Logger::MessageType::Error,
"this is an error",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"ERROR",
MB_OK | MB_ICONHAND)),
MakeTest("should log \"Exception: this is an exception\" with title \"How did you let this happen?\"",
no_errors,
make_tuple(Logger::MessageType::Wtf,
"what a terrible failure",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"How did you let this happen?",
MB_OK | MB_ICONHAND)),
MakeTest("should log \"Exception this is an exception\" with title \"Information\"",
no_errors,
make_tuple(Logger::MessageType::Info,
"this is some information",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"Information",
MB_OK | MB_ICONASTERISK)),
MakeTest("should log \"Exception: this is a warning with caught exception this is an exception\" with title "
"\"Warning\"",
no_errors,
make_tuple(Logger::MessageType::Warning,
"this is a warning",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"Warning",
MB_OK | MB_ICONEXCLAMATION)),
MakeTest("should log \"Exception: this is an exception\" with title \"Verbose\"",
no_errors,
make_tuple(Logger::MessageType::Verbose,
"this is verbose",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"Verbose",
MB_OK | MB_ICONASTERISK)),
MakeTest("should log \"Exception: this is an exception\" with title \"Unclassified\"",
no_errors,
make_tuple((Logger::MessageType)1000,
"unclassified message",
std::runtime_error("this is an exception"),
"Exception: this is an exception",
"Unclassified",
MB_OK | MB_ICONASTERISK)),
}));
}
int main(int argc, char *argv[]) {
TestResults results;
results += test_WindowsLogger_LogMessage();
results += test_WindowsLogger_LogErrorWithMessage();
results += test_WindowsLogger_LogErrorWithoutMessage();
PrintResults(cout, results);
return results.Failed() + results.Errors();
}
#endif // End defined(_WIN32)