Windows compatibility fixes
This commit is contained in:
parent
312ac2ec31
commit
1dd88f0a67
@ -13,15 +13,63 @@ using namespace cpputils::logging;
|
||||
namespace cpputils {
|
||||
|
||||
namespace {
|
||||
std::string exception_code_string(DWORD exception_code) {
|
||||
#define HANDLE_CODE(code) case code: return #code;
|
||||
switch (exception_code) {
|
||||
// List of exception codes taken from https://docs.microsoft.com/en-us/windows/desktop/Debug/getexceptioncode
|
||||
HANDLE_CODE(EXCEPTION_ACCESS_VIOLATION)
|
||||
HANDLE_CODE(EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
|
||||
HANDLE_CODE(EXCEPTION_BREAKPOINT)
|
||||
HANDLE_CODE(EXCEPTION_DATATYPE_MISALIGNMENT)
|
||||
HANDLE_CODE(EXCEPTION_FLT_DENORMAL_OPERAND)
|
||||
HANDLE_CODE(EXCEPTION_FLT_DIVIDE_BY_ZERO)
|
||||
HANDLE_CODE(EXCEPTION_FLT_INEXACT_RESULT)
|
||||
HANDLE_CODE(EXCEPTION_FLT_INVALID_OPERATION)
|
||||
HANDLE_CODE(EXCEPTION_FLT_OVERFLOW)
|
||||
HANDLE_CODE(EXCEPTION_FLT_STACK_CHECK)
|
||||
HANDLE_CODE(EXCEPTION_FLT_UNDERFLOW)
|
||||
HANDLE_CODE(EXCEPTION_GUARD_PAGE)
|
||||
HANDLE_CODE(EXCEPTION_ILLEGAL_INSTRUCTION)
|
||||
HANDLE_CODE(EXCEPTION_IN_PAGE_ERROR)
|
||||
HANDLE_CODE(EXCEPTION_INT_DIVIDE_BY_ZERO)
|
||||
HANDLE_CODE(EXCEPTION_INT_OVERFLOW)
|
||||
HANDLE_CODE(EXCEPTION_INVALID_DISPOSITION)
|
||||
HANDLE_CODE(EXCEPTION_INVALID_HANDLE)
|
||||
HANDLE_CODE(EXCEPTION_NONCONTINUABLE_EXCEPTION)
|
||||
HANDLE_CODE(EXCEPTION_PRIV_INSTRUCTION)
|
||||
HANDLE_CODE(EXCEPTION_SINGLE_STEP)
|
||||
HANDLE_CODE(EXCEPTION_STACK_OVERFLOW)
|
||||
HANDLE_CODE(STATUS_UNWIND_CONSOLIDATE)
|
||||
default:
|
||||
std::ostringstream str;
|
||||
str << "UNKNOWN_CODE(0x" << std::hex << exception_code << ")";
|
||||
return str.str();
|
||||
}
|
||||
#undef HANDLE_CODE
|
||||
}
|
||||
|
||||
struct SymInitializeRAII final {
|
||||
const HANDLE process;
|
||||
const bool success;
|
||||
|
||||
SymInitializeRAII()
|
||||
: process(GetCurrentProcess())
|
||||
, success(::SymInitialize(process, NULL, TRUE)) {
|
||||
}
|
||||
|
||||
~SymInitializeRAII() {
|
||||
::SymCleanup(process);
|
||||
}
|
||||
};
|
||||
|
||||
std::string backtrace_to_string(CONTEXT* context_record) {
|
||||
std::ostringstream backtrace;
|
||||
|
||||
HANDLE process = GetCurrentProcess();
|
||||
if (!::SymInitialize(process, NULL, TRUE)) {
|
||||
SymInitializeRAII sym;
|
||||
if (!sym.success) {
|
||||
DWORD error = GetLastError();
|
||||
backtrace << "[Can't get backtrace. SymInitialize failed with error code " << std::dec << error << "]\n";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Initialize stack walking.
|
||||
STACKFRAME64 stack_frame;
|
||||
memset(&stack_frame, 0, sizeof(stack_frame));
|
||||
@ -48,7 +96,7 @@ namespace cpputils {
|
||||
int i = 0;
|
||||
|
||||
while (StackWalk64(machine_type,
|
||||
GetCurrentProcess(),
|
||||
sym.process,
|
||||
GetCurrentThread(),
|
||||
&stack_frame,
|
||||
context_record,
|
||||
@ -61,13 +109,13 @@ namespace cpputils {
|
||||
|
||||
DWORD64 displacement = 0;
|
||||
|
||||
if (SymFromAddr(process, (DWORD64)stack_frame.AddrPC.Offset, &displacement, symbol))
|
||||
if (SymFromAddr(sym.process, (DWORD64)stack_frame.AddrPC.Offset, &displacement, symbol))
|
||||
{
|
||||
IMAGEHLP_MODULE64 moduleInfo;
|
||||
std::memset(&moduleInfo, 0, sizeof(IMAGEHLP_MODULE64));
|
||||
moduleInfo.SizeOfStruct = sizeof(moduleInfo);
|
||||
|
||||
if (::SymGetModuleInfo64(process, symbol->ModBase, &moduleInfo)) {
|
||||
if (::SymGetModuleInfo64(sym.process, symbol->ModBase, &moduleInfo)) {
|
||||
backtrace << moduleInfo.ModuleName << ":";
|
||||
}
|
||||
backtrace << "0x" << std::hex << (DWORD64)stack_frame.AddrPC.Offset << ": ";
|
||||
@ -83,7 +131,7 @@ namespace cpputils {
|
||||
IMAGEHLP_LINE64 line;
|
||||
SymSetOptions(SYMOPT_LOAD_LINES);
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (::SymGetLineFromAddr64(process, (DWORD64)stack_frame.AddrPC.Offset, &dwDisplacement, &line)) {
|
||||
if (::SymGetLineFromAddr64(sym.process, (DWORD64)stack_frame.AddrPC.Offset, &dwDisplacement, &line)) {
|
||||
backtrace << " at " << line.FileName << ":" << std::dec << line.LineNumber;
|
||||
}
|
||||
else {
|
||||
@ -101,7 +149,7 @@ namespace cpputils {
|
||||
LONG WINAPI TopLevelExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
|
||||
{
|
||||
std::string backtrace = backtrace_to_string(pExceptionInfo->ContextRecord);
|
||||
LOG(ERR, "Top level exception. Backtrace:\n{}", backtrace);
|
||||
LOG(ERR, "Top level exception. Code: {}. Backtrace:\n{}", exception_code_string(pExceptionInfo->ExceptionRecord->ExceptionCode), backtrace);
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
@ -116,7 +164,10 @@ namespace cpputils {
|
||||
}
|
||||
|
||||
void showBacktraceOnCrash() {
|
||||
SetUnhandledExceptionFilter(TopLevelExceptionHandler);
|
||||
PVOID result = AddVectoredExceptionHandler(1, TopLevelExceptionHandler);
|
||||
if (result == nullptr) {
|
||||
throw std::runtime_error("Error setting top level exception handler");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -39,7 +39,9 @@ Data CFB_Cipher<BlockCipher, KeySize>::encrypt(const CryptoPP::byte *plaintext,
|
||||
auto encryption = typename CryptoPP::CFB_Mode<BlockCipher>::Encryption(static_cast<const CryptoPP::byte*>(encKey.data()), encKey.BINARY_LENGTH, iv.data());
|
||||
Data ciphertext(ciphertextSize(plaintextSize));
|
||||
iv.ToBinary(ciphertext.data());
|
||||
encryption.ProcessData(static_cast<CryptoPP::byte*>(ciphertext.data()) + IV_SIZE, plaintext, plaintextSize);
|
||||
if (plaintextSize > 0) {
|
||||
encryption.ProcessData(static_cast<CryptoPP::byte*>(ciphertext.data()) + IV_SIZE, plaintext, plaintextSize);
|
||||
}
|
||||
return ciphertext;
|
||||
}
|
||||
|
||||
@ -53,7 +55,10 @@ boost::optional<Data> CFB_Cipher<BlockCipher, KeySize>::decrypt(const CryptoPP::
|
||||
const CryptoPP::byte *ciphertextData = ciphertext + IV_SIZE;
|
||||
auto decryption = typename CryptoPP::CFB_Mode<BlockCipher>::Decryption(static_cast<const CryptoPP::byte*>(encKey.data()), encKey.BINARY_LENGTH, ciphertextIV);
|
||||
Data plaintext(plaintextSize(ciphertextSize));
|
||||
decryption.ProcessData(static_cast<CryptoPP::byte*>(plaintext.data()), ciphertextData, plaintext.size());
|
||||
if (plaintext.size() > 0) {
|
||||
// TODO Shouldn't we pass in ciphertextSize instead of plaintext.size() here as last argument (and also in the if above)?
|
||||
decryption.ProcessData(static_cast<CryptoPP::byte*>(plaintext.data()), ciphertextData, plaintext.size());
|
||||
}
|
||||
return std::move(plaintext);
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
constexpr std::initializer_list<size_t> SIZES = {0, 1, 1024, 4096, 10*1024*1024};
|
||||
constexpr std::array<size_t, 5> SIZES = {0, 1, 1024, 4096, 10*1024*1024};
|
||||
#define TYPED_TEST_P_FOR_ALL_SIZES(TestName) \
|
||||
TYPED_TEST_P(BlockStoreTest, TestName) { \
|
||||
for (auto size: SIZES) { \
|
||||
|
@ -53,6 +53,8 @@ set(SOURCES
|
||||
value_type/ValueTypeTest.cpp
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME}_exit_status process/exit_status.cpp)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${SOURCES})
|
||||
target_link_libraries(${PROJECT_NAME} googletest cpp-utils)
|
||||
add_test(${PROJECT_NAME} ${PROJECT_NAME})
|
||||
|
@ -18,9 +18,14 @@ TEST(AssertTest_DebugBuild, DiesIfFalse) {
|
||||
}
|
||||
|
||||
TEST(AssertTest_DebugBuild, AssertMessage) {
|
||||
#if defined(_MSC_VER)
|
||||
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:\d+: my message)";
|
||||
#else
|
||||
constexpr const char* EXPECTED = R"(Assertion \[2==5\] failed in .*assert_debug_test.cpp:[0-9]+: my message)";
|
||||
#endif
|
||||
EXPECT_DEATH(
|
||||
ASSERT(2==5, "my message"),
|
||||
"Assertion \\[2==5\\] failed in .*/assert_debug_test.cpp:[0-9]+: my message"
|
||||
EXPECTED
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <gmock/gmock.h>
|
||||
#include <regex>
|
||||
|
||||
//Include the ASSERT macro for a release build
|
||||
#ifndef NDEBUG
|
||||
@ -26,9 +27,12 @@ TEST(AssertTest_ReleaseBuild, AssertMessage) {
|
||||
ASSERT(2==5, "my message");
|
||||
FAIL();
|
||||
} catch (const cpputils::AssertFailed &e) {
|
||||
EXPECT_THAT(e.what(), MatchesRegex(
|
||||
"Assertion \\[2==5\\] failed in .*/assert_release_test.cpp:26: my message.*"
|
||||
));
|
||||
std::string msg = e.what();
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
/*EXPECT_THAT(e.what(), MatchesRegex(
|
||||
R"(Assertion \[2==5\] failed in .*assert_release_test.cpp:27: my message)"
|
||||
));*/
|
||||
EXPECT_TRUE(std::regex_search(e.what(), std::regex(R"(Assertion \[2==5\] failed in .*assert_release_test.cpp:27: my message)")));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,62 +17,110 @@ TEST(BacktraceTest, ContainsTopLevelLine) {
|
||||
}
|
||||
|
||||
namespace {
|
||||
void nullptr_access() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
int* ptr = nullptr;
|
||||
*ptr = 5;
|
||||
void nullptr_access() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
int* ptr = nullptr;
|
||||
*ptr = 5;
|
||||
}
|
||||
}
|
||||
void raise_signal(int signal) {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::raise(signal);
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <Windows.h>
|
||||
namespace {
|
||||
void raise_sigsegv() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::RaiseException(EXCEPTION_ACCESS_VIOLATION, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
||||
}
|
||||
void raise_sigill() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::RaiseException(EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
||||
}
|
||||
void raise_code(DWORD exception_code) {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::RaiseException(exception_code, EXCEPTION_NONCONTINUABLE, 0, NULL);
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace {
|
||||
void raise_sigsegv() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::raise(SIGSEGV);
|
||||
}
|
||||
void raise_sigabrt() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::raise(SIGABRT);
|
||||
}
|
||||
void raise_sigill() {
|
||||
cpputils::showBacktraceOnCrash();
|
||||
::raise(SIGILL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnNullptrAccess) {
|
||||
EXPECT_DEATH(
|
||||
nullptr_access(),
|
||||
"cpputils::backtrace"
|
||||
nullptr_access(),
|
||||
"ShowBacktraceOnNullptrAccess_Test::TestBody"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigSegv) {
|
||||
EXPECT_DEATH(
|
||||
raise_signal(SIGSEGV),
|
||||
"cpputils::backtrace"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt) {
|
||||
EXPECT_DEATH(
|
||||
raise_signal(SIGABRT),
|
||||
"cpputils::backtrace"
|
||||
raise_sigsegv(),
|
||||
"ShowBacktraceOnSigSegv_Test::TestBody"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigIll) {
|
||||
EXPECT_DEATH(
|
||||
raise_signal(SIGILL),
|
||||
"cpputils::backtrace"
|
||||
);
|
||||
EXPECT_DEATH(
|
||||
raise_sigill(),
|
||||
"ShowBacktraceOnSigIll_Test::TestBody"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigSegv_ShowsCorrectSignalName) {
|
||||
#if !defined(_MSC_VER)
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt) {
|
||||
EXPECT_DEATH(
|
||||
raise_signal(SIGSEGV),
|
||||
"SIGSEGV"
|
||||
raise_sigabrt(),
|
||||
"ShowBacktraceOnSigAbrt_Test::TestBody"
|
||||
);
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigAbrt_ShowsCorrectSignalName) {
|
||||
EXPECT_DEATH(
|
||||
raise_signal(SIGABRT),
|
||||
"SIGABRT"
|
||||
);
|
||||
EXPECT_DEATH(
|
||||
raise_sigabrt(),
|
||||
"SIGABRT"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
constexpr const char* sigsegv_message = "SIGSEGV";
|
||||
constexpr const char* sigill_message = "SIGILL";
|
||||
#else
|
||||
constexpr const char* sigsegv_message = "EXCEPTION_ACCESS_VIOLATION";
|
||||
constexpr const char* sigill_message = "EXCEPTION_ILLEGAL_INSTRUCTION";
|
||||
#endif
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigSegv_ShowsCorrectSignalName) {
|
||||
EXPECT_DEATH(
|
||||
raise_sigsegv(),
|
||||
sigsegv_message
|
||||
);
|
||||
}
|
||||
|
||||
TEST(BacktraceTest, ShowBacktraceOnSigIll_ShowsCorrectSignalName) {
|
||||
EXPECT_DEATH(
|
||||
raise_signal(SIGILL),
|
||||
"SIGILL"
|
||||
raise_sigill(),
|
||||
sigill_message
|
||||
);
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
TEST(BacktraceTest, UnknownCode_ShowsCorrectSignalName) {
|
||||
EXPECT_DEATH(
|
||||
raise_code(0x12345678),
|
||||
"UNKNOWN_CODE\\(0x12345678\\)"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
|
||||
TYPED_TEST_CASE_P(CipherTest);
|
||||
|
||||
constexpr std::initializer_list<unsigned int> SIZES = {0, 1, 100, 1024, 5000, 1048576, 20971520};
|
||||
constexpr std::array<unsigned int, 7> SIZES = {0, 1, 100, 1024, 5000, 1048576, 20971520};
|
||||
|
||||
TYPED_TEST_P(CipherTest, Size) {
|
||||
for (auto size: SIZES) {
|
||||
|
@ -200,8 +200,12 @@ TEST_F(DataTest, LargesizeSize) {
|
||||
EXPECT_EQ(size, data.size());
|
||||
}
|
||||
#else
|
||||
#if defined(_MSC_VER)
|
||||
#pragma message This is not a 64bit architecture. Large size data tests are disabled.
|
||||
#else
|
||||
#warning This is not a 64bit architecture. Large size data tests are disabled.
|
||||
#endif
|
||||
#endif
|
||||
|
||||
TEST_F(DataTest, LoadingNonexistingFile) {
|
||||
TempFile file(false); // Pass false to constructor, so the tempfile is not created
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "testutils/LoggingTest.h"
|
||||
#include <regex>
|
||||
|
||||
using namespace cpputils::logging;
|
||||
using std::string;
|
||||
@ -8,7 +9,9 @@ class LoggingLevelTest: public LoggingTest {
|
||||
public:
|
||||
void EXPECT_DEBUG_LOG_ENABLED() {
|
||||
LOG(DEBUG, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*")));
|
||||
}
|
||||
|
||||
void EXPECT_DEBUG_LOG_DISABLED() {
|
||||
@ -18,7 +21,9 @@ public:
|
||||
|
||||
void EXPECT_INFO_LOG_ENABLED() {
|
||||
LOG(INFO, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
void EXPECT_INFO_LOG_DISABLED() {
|
||||
@ -28,7 +33,9 @@ public:
|
||||
|
||||
void EXPECT_WARNING_LOG_ENABLED() {
|
||||
LOG(WARN, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*")));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*"));
|
||||
}
|
||||
|
||||
void EXPECT_WARNING_LOG_DISABLED() {
|
||||
@ -38,7 +45,9 @@ public:
|
||||
|
||||
void EXPECT_ERROR_LOG_ENABLED() {
|
||||
LOG(ERR, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[error\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[error\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[error\\].*My log message.*")));
|
||||
}
|
||||
|
||||
void EXPECT_ERROR_LOG_DISABLED() {
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "testutils/LoggingTest.h"
|
||||
#include <regex>
|
||||
|
||||
/*
|
||||
* Contains test cases for the following logging interface:
|
||||
@ -13,7 +14,9 @@ TEST_F(LoggingTest, DefaultLoggerIsStderr) {
|
||||
string output = captureStderr([]{
|
||||
LOG(INFO, "My log message");
|
||||
});
|
||||
EXPECT_THAT(output, MatchesRegex(".*\\[Log\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(output, MatchesRegex(".*\\[Log\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(output, std::regex(".*\\[Log\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, SetLogger_NewLoggerIsUsed) {
|
||||
@ -21,13 +24,17 @@ TEST_F(LoggingTest, SetLogger_NewLoggerIsUsed) {
|
||||
string output = captureStderr([]{
|
||||
LOG(INFO, "My log message");
|
||||
});
|
||||
EXPECT_THAT(output, MatchesRegex(".*\\[MyTestLog2\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(output, MatchesRegex(".*\\[MyTestLog2\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(output, std::regex(".*\\[MyTestLog2\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, SetNonStderrLogger_LogsToNewLogger) {
|
||||
setLogger(mockLogger.get());
|
||||
logger()->info("My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(output, MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, SetNonStderrLogger_DoesNotLogToStderr) {
|
||||
@ -41,26 +48,34 @@ TEST_F(LoggingTest, SetNonStderrLogger_DoesNotLogToStderr) {
|
||||
TEST_F(LoggingTest, InfoLog) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(INFO, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, WarningLog) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(WARN, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[warning\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, DebugLog) {
|
||||
setLevel(DEBUG);
|
||||
setLogger(mockLogger.get());
|
||||
LOG(DEBUG, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[debug\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, ErrorLog) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(ERR, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[error\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[error\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[error\\].*My log message.*")));
|
||||
}
|
||||
|
||||
void logAndExit(const string &message) {
|
||||
@ -82,37 +97,49 @@ TEST_F(LoggingTest, LoggingAlsoWorksAfterFork) {
|
||||
TEST_F(LoggingTest, MessageIsConstChar) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(INFO, "My log message");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, MessageIsString) {
|
||||
setLogger(mockLogger.get());
|
||||
string msg = "My log message";
|
||||
LOG(INFO, msg);
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, FormatWithStringPlaceholder) {
|
||||
setLogger(mockLogger.get());
|
||||
string str = "placeholder";
|
||||
LOG(INFO, "My log message: {}", str);
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, FormatWithConstCharPlaceholder) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(INFO, "My log message: {}", "placeholder");
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: placeholder.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, FormatWithIntPlaceholder) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(INFO, "My log message: {}", 4);
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4.*")));
|
||||
}
|
||||
|
||||
TEST_F(LoggingTest, FormatWithMultiplePlaceholders) {
|
||||
setLogger(mockLogger.get());
|
||||
LOG(INFO, "My log message: {}, {}, {}", 4, "then", true);
|
||||
EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4, then, true.*"));
|
||||
// For some reason, the following doesn't seem to work in MSVC. Possibly because of the multiline string?
|
||||
//EXPECT_THAT(mockLogger.capturedLog(), MatchesRegex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4, then, true.*"));
|
||||
EXPECT_TRUE(std::regex_search(mockLogger.capturedLog(), std::regex(".*\\[MockLogger\\].*\\[info\\].*My log message: 4, then, true.*")));
|
||||
}
|
||||
|
@ -4,86 +4,97 @@
|
||||
using cpputils::Subprocess;
|
||||
using cpputils::SubprocessError;
|
||||
|
||||
namespace {
|
||||
std::string exit_with_message_and_status(const char* message, int status) {
|
||||
#if defined(_MSC_VER)
|
||||
constexpr const char* executable = "cpp-utils-test_exit_status.exe";
|
||||
#else
|
||||
constexpr const char* executable = "./test/cpp-utils/cpp-utils-test_exit_status";
|
||||
#endif
|
||||
return std::string(executable) + " \"" + message + "\" " + std::to_string(status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_success_output) {
|
||||
EXPECT_EQ("hello\n", Subprocess::check_call("echo hello").output);
|
||||
EXPECT_EQ("hello", Subprocess::check_call(exit_with_message_and_status("hello", 0)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_successwithemptyoutput_output) {
|
||||
EXPECT_EQ("", Subprocess::check_call("exit 0").output);
|
||||
EXPECT_EQ("", Subprocess::check_call(exit_with_message_and_status("", 0)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_success_exitcode) {
|
||||
EXPECT_EQ(0, Subprocess::check_call("echo hello").exitcode);
|
||||
EXPECT_EQ(0, Subprocess::check_call(exit_with_message_and_status("hello", 0)).exitcode);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_successwithemptyoutput_exitcode) {
|
||||
EXPECT_EQ(0, Subprocess::check_call("exit 0").exitcode);
|
||||
EXPECT_EQ(0, Subprocess::check_call(exit_with_message_and_status("", 0)).exitcode);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_error) {
|
||||
EXPECT_THROW(
|
||||
Subprocess::check_call("exit 1"),
|
||||
Subprocess::check_call(exit_with_message_and_status("", 1)),
|
||||
SubprocessError
|
||||
);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_error5) {
|
||||
EXPECT_THROW(
|
||||
Subprocess::check_call("exit 5"),
|
||||
Subprocess::check_call(exit_with_message_and_status("", 5)),
|
||||
SubprocessError
|
||||
);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_errorwithoutput) {
|
||||
EXPECT_THROW(
|
||||
Subprocess::check_call("echo hello; exit 1"),
|
||||
Subprocess::check_call(exit_with_message_and_status("hello", 1)),
|
||||
SubprocessError
|
||||
);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, CheckCall_error5withoutput) {
|
||||
EXPECT_THROW(
|
||||
Subprocess::check_call("echo hello; exit 5"),
|
||||
Subprocess::check_call(exit_with_message_and_status("hello", 5)),
|
||||
SubprocessError
|
||||
);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_success_exitcode) {
|
||||
EXPECT_EQ(0, Subprocess::call("echo hello").exitcode);
|
||||
EXPECT_EQ(0, Subprocess::call(exit_with_message_and_status("hello", 0)).exitcode);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_success_output) {
|
||||
EXPECT_EQ("hello\n", Subprocess::call("echo hello").output);
|
||||
EXPECT_EQ("hello", Subprocess::call(exit_with_message_and_status("hello", 0)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_error_exitcode) {
|
||||
EXPECT_EQ(1, Subprocess::call("exit 1").exitcode);
|
||||
EXPECT_EQ(1, Subprocess::call(exit_with_message_and_status("", 1)).exitcode);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_error_output) {
|
||||
EXPECT_EQ("", Subprocess::call("exit 1").output);
|
||||
EXPECT_EQ("", Subprocess::call(exit_with_message_and_status("", 1)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_error5_exitcode) {
|
||||
EXPECT_EQ(5, Subprocess::call("exit 5").exitcode);
|
||||
EXPECT_EQ(5, Subprocess::call(exit_with_message_and_status("", 5)).exitcode);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_error5_output) {
|
||||
EXPECT_EQ("", Subprocess::call("exit 1").output);
|
||||
EXPECT_EQ("", Subprocess::call(exit_with_message_and_status("", 1)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_errorwithoutput_output) {
|
||||
EXPECT_EQ("hello\n", Subprocess::call("echo hello; exit 1").output);
|
||||
EXPECT_EQ("hello", Subprocess::call(exit_with_message_and_status("hello", 1)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_errorwithoutput_exitcode) {
|
||||
EXPECT_EQ(1, Subprocess::call("echo hello; exit 1").exitcode);
|
||||
EXPECT_EQ(1, Subprocess::call(exit_with_message_and_status("hello", 1)).exitcode);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_error5withoutput_output) {
|
||||
EXPECT_EQ("hello\n", Subprocess::call("echo hello; exit 5").output);
|
||||
EXPECT_EQ("hello", Subprocess::call(exit_with_message_and_status("hello", 5)).output);
|
||||
}
|
||||
|
||||
TEST(SubprocessTest, Call_error5withoutput_exitcode) {
|
||||
EXPECT_EQ(5, Subprocess::call("echo hello; exit 5").exitcode);
|
||||
EXPECT_EQ(5, Subprocess::call(exit_with_message_and_status("hello", 5)).exitcode);
|
||||
}
|
||||
|
15
test/cpp-utils/process/exit_status.cpp
Normal file
15
test/cpp-utils/process/exit_status.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
// This is a small executable that prints its first argument and exits with the exit status in its second argument
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 3) {
|
||||
std::cerr << "Wrong number of arguments" << std::endl;
|
||||
abort();
|
||||
}
|
||||
|
||||
std::cout << argv[1];
|
||||
|
||||
int exit_status = std::atoi(argv[2]);
|
||||
return exit_status;
|
||||
}
|
@ -17,9 +17,6 @@ TEST(HomedirTest, AppDataDirIsValid) {
|
||||
auto dir = HomeDirectory::getXDGDataDir();
|
||||
EXPECT_FALSE(dir.empty());
|
||||
EXPECT_GE(std::distance(dir.begin(), dir.end()), 2u); // has at least two components
|
||||
for(const auto& component : dir) {
|
||||
EXPECT_TRUE(component.string() == "/" || bf::native(component.string()));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(HomedirTest, FakeHomeDirectorySetsHomedirCorrectly) {
|
||||
|
Loading…
Reference in New Issue
Block a user