Merge commit '8e97373d883c06e1c73791849561d1311c880bc0' as 'libs/loguru'
This commit is contained in:
80
libs/loguru/test/CMakeLists.txt
Normal file
80
libs/loguru/test/CMakeLists.txt
Normal file
@@ -0,0 +1,80 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
project(loguru_test)
|
||||
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING
|
||||
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
|
||||
endif(NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
MESSAGE(STATUS "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}")
|
||||
|
||||
if(MSVC)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /Wall")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Werror -Wall -Wextra -pedantic -fsanitize=address -fno-omit-frame-pointer")
|
||||
endif()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Weverything")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-c++98-compat-pedantic")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-noreturn")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-missing-prototypes")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
|
||||
endif() # Clang
|
||||
|
||||
add_executable(loguru_test loguru_test.cpp)
|
||||
|
||||
find_package(Threads)
|
||||
target_link_libraries(loguru_test ${CMAKE_THREAD_LIBS_INIT}) # For pthreads
|
||||
if(NOT WIN32)
|
||||
target_link_libraries(loguru_test dl) # For ldl
|
||||
endif()
|
||||
|
||||
enable_testing()
|
||||
|
||||
if(NOT WIN32)
|
||||
# Sadly, Windows doesn't allow us to safely run the following tests
|
||||
list(APPEND ExtraFailureTests
|
||||
SIGSEGV
|
||||
throw_on_signal)
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
list(APPEND ExtraFailureTests
|
||||
assert)
|
||||
endif()
|
||||
|
||||
# Failure Tests
|
||||
foreach(Test
|
||||
ABORT_F
|
||||
ABORT_S
|
||||
LOG_F_FATAL
|
||||
LOG_S_FATAL
|
||||
CHECK_NOTNULL_F
|
||||
CHECK_F
|
||||
CHECK_EQ_F_int
|
||||
CHECK_EQ_F_unsigned
|
||||
CHECK_EQ_F_size_t
|
||||
CHECK_EQ_F
|
||||
CHECK_EQ_F_message
|
||||
CHECK_EQ_S
|
||||
CHECK_LT_S
|
||||
CHECK_LT_S_message
|
||||
deep_abort
|
||||
abort
|
||||
error_context
|
||||
throw_on_fatal
|
||||
${ExtraFailureTests}
|
||||
)
|
||||
add_test(NAME loguru_test_${Test}
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_LIST_DIR}/fail_test_wrapper.cmake
|
||||
$<TARGET_FILE:loguru_test> ${Test})
|
||||
endforeach()
|
||||
|
||||
# Success Tests
|
||||
foreach(Test
|
||||
callback)
|
||||
add_test(loguru_test_${Test} loguru_test ${Test})
|
||||
endforeach()
|
||||
50
libs/loguru/test/appveyor.cmake
Normal file
50
libs/loguru/test/appveyor.cmake
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env cmake -P
|
||||
# Group AppVeyor builds to use fewer VM instances and upload useful artifacts from each.
|
||||
find_program(AppVeyor appveyor)
|
||||
if(NOT AppVeyor)
|
||||
message(FATAL_ERROR "script specific to appveyor only")
|
||||
endif()
|
||||
|
||||
function(message type) # overriding CMake built-in message function for AppVeyor
|
||||
set(msg "${ARGV}")
|
||||
if(type STREQUAL FATAL_ERROR OR type STREQUAL SEND_ERROR)
|
||||
set(msg "${ARGN}")
|
||||
set(options -Category Error)
|
||||
elseif(type STREQUAL WARNING OR type STREQUAL AUTHOR_WARNING)
|
||||
set(msg "${ARGN}")
|
||||
set(options -Category Warning)
|
||||
elseif(type STREQUAL STATUS)
|
||||
set(msg "${ARGN}")
|
||||
set(options -Category Information)
|
||||
endif()
|
||||
execute_process(COMMAND ${AppVeyor} AddMessage "${msg}" ${options})
|
||||
|
||||
_message(${ARGV}) # the built-in functionality
|
||||
endfunction()
|
||||
|
||||
function(BuildAndRun)
|
||||
if(DEFINED Generator)
|
||||
string(REPLACE " " "" gen "${Generator}/") # Remove spaces from generator
|
||||
endif()
|
||||
set(BUILD_DIR "${CMAKE_CURRENT_LIST_DIR}/build/${gen}${Configuration}")
|
||||
message("Building ${gen}${Configuration}")
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/build_and_run.cmake)
|
||||
message("Built ${gen}${Configuration}")
|
||||
execute_process(COMMAND ${CMAKE_COMMAND} -E tar czf "${BUILD_DIR}/Testing.zip" "${BUILD_DIR}/Testing")
|
||||
execute_process(COMMAND ${AppVeyor} PushArtifact "${BUILD_DIR}/Testing.zip" -FileName "${gen}${Configuration}.zip")
|
||||
endfunction()
|
||||
|
||||
foreach(Configuration "Debug" "Release")
|
||||
if(WIN32)
|
||||
foreach(Generator
|
||||
"Visual Studio 14 2015"
|
||||
"Visual Studio 14 2015 Win64"
|
||||
"Visual Studio 15 2017"
|
||||
"Visual Studio 15 2017 Win64"
|
||||
)
|
||||
BuildAndRun()
|
||||
endforeach()
|
||||
elseif(UNIX)
|
||||
BuildAndRun()
|
||||
endif()
|
||||
endforeach()
|
||||
21
libs/loguru/test/build.sh
Executable file
21
libs/loguru/test/build.sh
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
set -e # Fail on error
|
||||
|
||||
ROOT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
mkdir -p build
|
||||
cd build
|
||||
|
||||
cmake ..
|
||||
|
||||
# Use GCC:
|
||||
# cmake -DCMAKE_C_COMPILER=/usr/bin/gcc -DCMAKE_CXX_COMPILER=/usr/bin/g++ ..
|
||||
|
||||
# Use GCC5:
|
||||
# cmake -DCMAKE_C_COMPILER=/usr/bin/gcc-5 -DCMAKE_CXX_COMPILER=/usr/bin/g++-5 ..
|
||||
|
||||
# Use clang-3.7:
|
||||
# cmake -DCMAKE_C_COMPILER=/usr/bin/clang-3.7 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-3.7 ..
|
||||
|
||||
make
|
||||
45
libs/loguru/test/build_and_run.cmake
Normal file
45
libs/loguru/test/build_and_run.cmake
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env cmake -P
|
||||
|
||||
# for lack of an equivalent of `set -e` in bash
|
||||
macro(EXEC_CMD_CHECK)
|
||||
message("running ${ARGN}")
|
||||
execute_process(COMMAND ${ARGN} RESULT_VARIABLE CMD_RESULT)
|
||||
if(CMD_RESULT)
|
||||
message(FATAL_ERROR "Error running ${ARGN}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Read the configuration from the environement
|
||||
if(NOT DEFINED Configuration AND DEFINED ENV{Configuration})
|
||||
set(Configuration $ENV{Configuration})
|
||||
endif()
|
||||
# to override the default configuration: ex. -DConfiguration=Release
|
||||
if(DEFINED Configuration)
|
||||
list(APPEND CMAKE_EXTRA_ARGS "-DCMAKE_BUILD_TYPE=${Configuration}")
|
||||
set(CMAKE_BUILD_EXTRA_ARGS --config ${Configuration})
|
||||
set(CTEST_EXTRA_ARGS -C ${Configuration})
|
||||
endif()
|
||||
|
||||
# The generator also, if we have an entry in the envirnoment
|
||||
if(NOT DEFINED Generator AND DEFINED ENV{Generator})
|
||||
set(Generator $ENV{Generator})
|
||||
endif()
|
||||
# to override the default generator: ex. -DGenerator=Ninja
|
||||
if(DEFINED Generator)
|
||||
list(APPEND CMAKE_EXTRA_ARGS "-G${Generator}")
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED BUILD_DIR)
|
||||
set(BUILD_DIR ${CMAKE_CURRENT_LIST_DIR}/build)
|
||||
endif()
|
||||
file(MAKE_DIRECTORY ${BUILD_DIR})
|
||||
|
||||
# cd build && cmake .. && cd -
|
||||
EXEC_CMD_CHECK(${CMAKE_COMMAND} ${CMAKE_EXTRA_ARGS} ${CMAKE_CURRENT_LIST_DIR}
|
||||
WORKING_DIRECTORY ${BUILD_DIR})
|
||||
|
||||
# platform-independent equivalent of `make`
|
||||
EXEC_CMD_CHECK(${CMAKE_COMMAND} --build ${BUILD_DIR} ${CMAKE_BUILD_EXTRA_ARGS})
|
||||
|
||||
EXEC_CMD_CHECK(${CMAKE_CTEST_COMMAND} ${CTEST_EXTRA_ARGS} --output-on-failure
|
||||
WORKING_DIRECTORY ${BUILD_DIR})
|
||||
57
libs/loguru/test/build_and_run.sh
Executable file
57
libs/loguru/test/build_and_run.sh
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/bin/bash
|
||||
set -e # Fail on error
|
||||
|
||||
ROOT_DIR=$(cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd)
|
||||
|
||||
$ROOT_DIR/build.sh
|
||||
|
||||
cd $ROOT_DIR/build/
|
||||
|
||||
function test_failure
|
||||
{
|
||||
echo ""
|
||||
./loguru_test $1 && echo "Expected command to fail!" && exit 1
|
||||
echo ""
|
||||
echo ""
|
||||
}
|
||||
|
||||
function test_success
|
||||
{
|
||||
echo ""
|
||||
./loguru_test $1 || echo "Expected command to succeed!"
|
||||
echo ""
|
||||
echo ""
|
||||
}
|
||||
|
||||
echo "---------------------------------------------------------"
|
||||
echo "Testing failures..."
|
||||
echo "---------------------------------------------------------"
|
||||
test_failure "ABORT_F"
|
||||
test_failure "ABORT_S"
|
||||
test_failure "assert"
|
||||
test_failure "LOG_F_FATAL"
|
||||
test_failure "LOG_S_FATAL"
|
||||
test_failure "CHECK_NOTNULL_F"
|
||||
test_failure "CHECK_F"
|
||||
test_failure "CHECK_EQ_F_int"
|
||||
test_failure "CHECK_EQ_F_unsigned"
|
||||
test_failure "CHECK_EQ_F_size_t"
|
||||
test_failure "CHECK_EQ_F"
|
||||
test_failure "CHECK_EQ_F_message"
|
||||
test_failure "CHECK_EQ_S"
|
||||
test_failure "CHECK_LT_S"
|
||||
test_failure "CHECK_LT_S_message"
|
||||
test_failure "deep_abort"
|
||||
test_failure "SIGSEGV"
|
||||
test_failure "abort"
|
||||
test_failure "error_context"
|
||||
test_failure "throw_on_fatal"
|
||||
test_failure "throw_on_signal"
|
||||
test_success "callback"
|
||||
echo "---------------------------------------------------------"
|
||||
echo "ALL TESTS PASSED!"
|
||||
echo "---------------------------------------------------------"
|
||||
|
||||
./loguru_test $@
|
||||
|
||||
./loguru_test hang
|
||||
24
libs/loguru/test/fail_test_wrapper.cmake
Normal file
24
libs/loguru/test/fail_test_wrapper.cmake
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env cmake -P
|
||||
cmake_minimum_required(VERSION 2.8.7)
|
||||
|
||||
get_filename_component(CurrentFile ${CMAKE_CURRENT_LIST_FILE} NAME)
|
||||
|
||||
# The script is invoked as cmake -P <script name> <loguru_test> <arg(s)>
|
||||
# the following loop extracts the arguments after the one matching the script name
|
||||
foreach(i RANGE 0 ${CMAKE_ARGC})
|
||||
if(CollectArgs)
|
||||
list(APPEND TestArgs ${CMAKE_ARGV${i}})
|
||||
elseif(CMAKE_ARGV${i} MATCHES "${CurrentFile}$")
|
||||
set(CollectArgs true)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# TestArgs contains <loguru_test> <arg(s)>
|
||||
execute_process(COMMAND ${TestArgs}
|
||||
RESULT_VARIABLE CmdResult)
|
||||
|
||||
# To invert the failure logic
|
||||
if(NOT CmdResult)
|
||||
# the wrapper must fail if the child process returned success
|
||||
message(FATAL_ERROR "${TestArgs} passed.")
|
||||
endif()
|
||||
432
libs/loguru/test/loguru_test.cpp
Normal file
432
libs/loguru/test/loguru_test.cpp
Normal file
@@ -0,0 +1,432 @@
|
||||
// Include loguru first to test that it needs no dependencies:
|
||||
#define LOGURU_FILENAME_WIDTH 16
|
||||
#define LOGURU_WITH_STREAMS 1
|
||||
#define LOGURU_REDEFINE_ASSERT 1
|
||||
#define LOGURU_USE_FMTLIB 0
|
||||
#define LOGURU_WITH_FILEABS 0
|
||||
// #define LOGURU_STACKTRACES 1
|
||||
// #define LOGURU_RTTI 1
|
||||
#include "../loguru.cpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
void the_one_where_the_problem_is(const std::vector<std::string>& v) {
|
||||
ABORT_F("Abort deep in stack trace, msg: %s", v[0].c_str());
|
||||
}
|
||||
void deep_abort_1(const std::vector<std::string>& v) { the_one_where_the_problem_is(v); }
|
||||
void deep_abort_2(const std::vector<std::string>& v) { deep_abort_1(v); }
|
||||
void deep_abort_3(const std::vector<std::string>& v) { deep_abort_2(v); }
|
||||
void deep_abort_4(const std::vector<std::string>& v) { deep_abort_3(v); }
|
||||
void deep_abort_5(const std::vector<std::string>& v) { deep_abort_4(v); }
|
||||
void deep_abort_6(const std::vector<std::string>& v) { deep_abort_5(v); }
|
||||
void deep_abort_7(const std::vector<std::string>& v) { deep_abort_6(v); }
|
||||
void deep_abort_8(const std::vector<std::string>& v) { deep_abort_7(v); }
|
||||
void deep_abort_9(const std::vector<std::string>& v) { deep_abort_8(v); }
|
||||
void deep_abort_10(const std::vector<std::string>& v) { deep_abort_9(v); }
|
||||
|
||||
void sleep_ms(int ms)
|
||||
{
|
||||
LOG_F(3, "Sleeping for %d ms", ms);
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
|
||||
}
|
||||
|
||||
void test_thread_names()
|
||||
{
|
||||
LOG_SCOPE_FUNCTION(INFO);
|
||||
|
||||
{
|
||||
char thread_name[17];
|
||||
loguru::get_thread_name(thread_name, sizeof(thread_name), false);
|
||||
LOG_F(INFO, "Hello from main thread ('%s')", thread_name);
|
||||
}
|
||||
|
||||
auto a = std::thread([](){
|
||||
char thread_name[17];
|
||||
loguru::get_thread_name(thread_name, sizeof(thread_name), false);
|
||||
LOG_F(INFO, "Hello from nameless thread ('%s')", thread_name);
|
||||
});
|
||||
|
||||
auto b = std::thread([](){
|
||||
loguru::set_thread_name("renderer");
|
||||
char thread_name[17];
|
||||
loguru::get_thread_name(thread_name, sizeof(thread_name), false);
|
||||
LOG_F(INFO, "Hello from render thread ('%s')", thread_name);
|
||||
});
|
||||
|
||||
auto c = std::thread([](){
|
||||
loguru::set_thread_name("abcdefghijklmnopqrstuvwxyz");
|
||||
char thread_name[17];
|
||||
loguru::get_thread_name(thread_name, sizeof(thread_name), false);
|
||||
LOG_F(INFO, "Hello from thread with a very long name ('%s')", thread_name);
|
||||
});
|
||||
|
||||
a.join();
|
||||
b.join();
|
||||
c.join();
|
||||
}
|
||||
|
||||
void test_scopes()
|
||||
{
|
||||
LOG_SCOPE_FUNCTION(INFO);
|
||||
|
||||
LOG_F(INFO, "Should be indented one step");
|
||||
LOG_F(1, "First thing");
|
||||
LOG_F(1, "Second thing");
|
||||
|
||||
{
|
||||
LOG_SCOPE_F(1, "Some indentation at level 1");
|
||||
LOG_F(INFO, "Should only be indented one more step iff verbosity is 1 or higher");
|
||||
LOG_F(2, "Some info");
|
||||
sleep_ms(123);
|
||||
}
|
||||
|
||||
sleep_ms(64);
|
||||
}
|
||||
|
||||
void test_levels()
|
||||
{
|
||||
LOG_SCOPE_FUNCTION(INFO);
|
||||
{
|
||||
VLOG_SCOPE_F(1, "Scope with verbosity 1");
|
||||
LOG_F(3, "Only visible with -v 3 or higher");
|
||||
LOG_F(2, "Only visible with -v 2 or higher");
|
||||
LOG_F(1, "Only visible with -v 1 or higher");
|
||||
}
|
||||
LOG_F(0, "LOG_F(0)");
|
||||
LOG_F(INFO, "This is some INFO");
|
||||
LOG_F(WARNING, "This is a WARNING");
|
||||
LOG_F(ERROR, "This is a serious ERROR");
|
||||
}
|
||||
|
||||
#if LOGURU_WITH_STREAMS
|
||||
void test_stream()
|
||||
{
|
||||
LOG_SCOPE_FUNCTION(INFO);
|
||||
LOG_S(INFO) << "Testing stream-logging.";
|
||||
LOG_S(INFO) << "First line" << std::endl << "Seconds line.";
|
||||
LOG_S(1) << "Stream-logging with verbosity 1";
|
||||
LOG_S(2) << "Stream-logging with verbosity 2";
|
||||
LOG_S(3) << "Stream-logging with verbosity 3";
|
||||
LOG_IF_S(INFO, true) << "Should be visible";
|
||||
LOG_IF_S(INFO, false) << "SHOULD NOT BE VISIBLE";
|
||||
LOG_IF_S(1, true) << "Should be visible if verbosity is at least 1";
|
||||
LOG_IF_S(1, false) << "SHOULD NOT BE VISIBLE";
|
||||
CHECK_LT_S(1, 2);
|
||||
CHECK_GT_S(3, 2) << "Weird";
|
||||
}
|
||||
#endif
|
||||
|
||||
int some_expensive_operation() { static int r=31; sleep_ms(132); return r++; }
|
||||
const int BAD = 32;
|
||||
|
||||
int always_increasing() { static int x = 0; return x++; }
|
||||
|
||||
int main_test(int argc, char* argv[])
|
||||
{
|
||||
loguru::init(argc, argv);
|
||||
LOG_SCOPE_FUNCTION(INFO);
|
||||
LOG_F(INFO, "Doing some stuff...");
|
||||
for (int i=0; i<2; ++i) {
|
||||
LOG_SCOPE_F(1, "Iteration %d", i);
|
||||
auto result = some_expensive_operation();
|
||||
LOG_IF_F(WARNING, result == BAD, "Bad result");
|
||||
}
|
||||
LOG_F(INFO, "Time to go!");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void test_SIGSEGV_0()
|
||||
{
|
||||
LOG_F(INFO, "Intentionally writing to nullptr:");
|
||||
int* ptr = nullptr;
|
||||
*ptr = 42;
|
||||
LOG_F(FATAL, "We shouldn't get here");
|
||||
}
|
||||
void test_SIGSEGV_1() { test_SIGSEGV_0(); }
|
||||
void test_SIGSEGV_2() { test_SIGSEGV_1(); }
|
||||
|
||||
void test_abort_0()
|
||||
{
|
||||
LOG_F(INFO, "Calling std::abort");
|
||||
std::abort();
|
||||
}
|
||||
void test_abort_1() { test_abort_0(); }
|
||||
void test_abort_2() { test_abort_1(); }
|
||||
|
||||
struct CustomType
|
||||
{
|
||||
std::string contents;
|
||||
};
|
||||
|
||||
namespace loguru {
|
||||
Text ec_to_text(const CustomType* custom)
|
||||
{
|
||||
return Text(strdup(custom->contents.c_str()));
|
||||
}
|
||||
} // namespace loguru
|
||||
|
||||
void test_error_contex()
|
||||
{
|
||||
{ ERROR_CONTEXT("THIS SHOULDN'T BE PRINTED", "scoped"); }
|
||||
ERROR_CONTEXT("Parent thread value", 42);
|
||||
{ ERROR_CONTEXT("THIS SHOULDN'T BE PRINTED", "scoped"); }
|
||||
char parent_thread_name[17];
|
||||
loguru::get_thread_name(parent_thread_name, sizeof(parent_thread_name), false);
|
||||
ERROR_CONTEXT("Parent thread name", &parent_thread_name[0]);
|
||||
|
||||
const auto parent_ec_handle = loguru::get_thread_ec_handle();
|
||||
|
||||
std::thread([=]{
|
||||
loguru::set_thread_name("EC test thread");
|
||||
ERROR_CONTEXT("parent error context", parent_ec_handle);
|
||||
{ ERROR_CONTEXT("THIS SHOULDN'T BE PRINTED", "scoped"); }
|
||||
ERROR_CONTEXT("const char*", "test string");
|
||||
ERROR_CONTEXT("integer", 42);
|
||||
ERROR_CONTEXT("float", 3.14f);
|
||||
ERROR_CONTEXT("double", 3.14);
|
||||
{ ERROR_CONTEXT("THIS SHOULDN'T BE PRINTED", "scoped"); }
|
||||
ERROR_CONTEXT("char A", 'A');
|
||||
ERROR_CONTEXT("char backslash", '\\');
|
||||
ERROR_CONTEXT("char double-quote", '\"');
|
||||
ERROR_CONTEXT("char single-quote", '\'');
|
||||
ERROR_CONTEXT("char zero", '\0');
|
||||
ERROR_CONTEXT("char bell", '\b');
|
||||
ERROR_CONTEXT("char feed", '\f');
|
||||
ERROR_CONTEXT("char newline", '\n');
|
||||
ERROR_CONTEXT("char return", '\r');
|
||||
ERROR_CONTEXT("char tab", '\t');
|
||||
ERROR_CONTEXT("char x13", '\u0013');
|
||||
{ ERROR_CONTEXT("THIS SHOULDN'T BE PRINTED", "scoped"); }
|
||||
CustomType custom{"custom_contents"};
|
||||
ERROR_CONTEXT("CustomType", &custom);
|
||||
ABORT_F("Intentional abort");
|
||||
}).join();
|
||||
}
|
||||
|
||||
void test_hang_0()
|
||||
{
|
||||
LOG_F(INFO, "Press ctrl-C to kill.");
|
||||
for(;;) {
|
||||
// LOG_F(INFO, "Press ctrl-C to break out of this infinite loop.");
|
||||
}
|
||||
}
|
||||
void test_hang_1() { test_hang_0(); }
|
||||
void test_hang_2() { test_hang_1(); }
|
||||
|
||||
void throw_on_fatal()
|
||||
{
|
||||
loguru::set_fatal_handler([](const loguru::Message& message){
|
||||
LOG_F(INFO, "Throwing exception...");
|
||||
throw std::runtime_error(std::string(message.prefix) + message.message);
|
||||
});
|
||||
{
|
||||
LOG_SCOPE_F(INFO, "CHECK_F throw + catch");
|
||||
try {
|
||||
CHECK_F(false, "some CHECK_F message");
|
||||
} catch (std::runtime_error& e) {
|
||||
LOG_F(INFO, "CHECK_F threw this: '%s'", e.what());
|
||||
}
|
||||
}
|
||||
#if LOGURU_WITH_STREAMS
|
||||
{
|
||||
LOG_SCOPE_F(INFO, "CHECK_S throw + catch");
|
||||
try {
|
||||
CHECK_S(false) << "Some CHECK_S message";
|
||||
} catch (std::runtime_error& e) {
|
||||
LOG_F(INFO, "CHECK_S threw this: '%s'", e.what());
|
||||
}
|
||||
}
|
||||
LOG_F(INFO, "Trying an uncaught exception:");
|
||||
CHECK_S(false);
|
||||
#else
|
||||
CHECK_F(false);
|
||||
#endif // LOGURU_WITH_STREAMS
|
||||
}
|
||||
|
||||
void throw_on_signal()
|
||||
{
|
||||
loguru::set_fatal_handler([](const loguru::Message& message){
|
||||
LOG_F(INFO, "Throwing exception...");
|
||||
throw std::runtime_error(std::string(message.prefix) + message.message);
|
||||
});
|
||||
test_SIGSEGV_0();
|
||||
}
|
||||
|
||||
// void die(std::ofstream& of)
|
||||
// {
|
||||
// (void)of;
|
||||
// test_hang_2();
|
||||
// }
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
struct CallbackTester
|
||||
{
|
||||
size_t num_print = 0;
|
||||
size_t num_flush = 0;
|
||||
size_t num_close = 0;
|
||||
};
|
||||
|
||||
void callbackPrint(void* user_data, const loguru::Message& message)
|
||||
{
|
||||
printf("Custom callback: %s%s\n", message.prefix, message.message);
|
||||
reinterpret_cast<CallbackTester*>(user_data)->num_print += 1;
|
||||
}
|
||||
|
||||
void callbackFlush(void* user_data)
|
||||
{
|
||||
printf("Custom callback flush\n");
|
||||
reinterpret_cast<CallbackTester*>(user_data)->num_flush += 1;
|
||||
}
|
||||
|
||||
void callbackClose(void* user_data)
|
||||
{
|
||||
printf("Custom callback close\n");
|
||||
reinterpret_cast<CallbackTester*>(user_data)->num_close += 1;
|
||||
}
|
||||
|
||||
void test_log_callback()
|
||||
{
|
||||
CallbackTester tester;
|
||||
loguru::add_callback(
|
||||
"user_callback", callbackPrint, &tester,
|
||||
loguru::Verbosity_INFO, callbackClose, callbackFlush);
|
||||
CHECK_EQ_F(tester.num_print, 0u);
|
||||
LOG_F(INFO, "Test print");
|
||||
CHECK_EQ_F(tester.num_print, 1u);
|
||||
CHECK_EQ_F(tester.num_close, 0u);
|
||||
CHECK_EQ_F(tester.num_flush, 1u);
|
||||
loguru::flush();
|
||||
CHECK_EQ_F(tester.num_flush, 2u);
|
||||
loguru::remove_callback("user_callback");
|
||||
CHECK_EQ_F(tester.num_close, 1u);
|
||||
}
|
||||
|
||||
#if defined _WIN32 && defined _DEBUG
|
||||
#define USE_WIN_DBG_HOOK
|
||||
static int winDbgHook(int reportType, char *message, int *)
|
||||
{
|
||||
fprintf(stderr, "Report type: %d\nMessage: %s\n", reportType,
|
||||
(nullptr != message ? message : "nullptr message"));
|
||||
return 1; // To prevent the Abort, Retry, Ignore dialog
|
||||
}
|
||||
#endif
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
#ifdef USE_WIN_DBG_HOOK
|
||||
_CrtSetReportHook2(_CRT_RPTHOOK_INSTALL, winDbgHook);
|
||||
#endif
|
||||
|
||||
// loguru::g_preamble = false;
|
||||
|
||||
if (argc > 1 && argv[1] == std::string("test"))
|
||||
{
|
||||
return main_test(argc, argv);
|
||||
}
|
||||
|
||||
loguru::init(argc, argv);
|
||||
|
||||
// auto verbose_type_name = loguru::demangle(typeid(std::ofstream).name());
|
||||
// loguru::add_stack_cleanup(verbose_type_name.c_str(), "std::ofstream");
|
||||
// std::ofstream os;
|
||||
// die(os);
|
||||
|
||||
if (argc == 1)
|
||||
{
|
||||
loguru::add_file("latest_readable.log", loguru::Truncate, loguru::Verbosity_INFO);
|
||||
loguru::add_file("everything.log", loguru::Append, loguru::Verbosity_MAX);
|
||||
#ifdef LOGURU_SYSLOG
|
||||
loguru::add_syslog("loguru_test", loguru::Verbosity_MAX);
|
||||
#endif
|
||||
|
||||
LOG_F(INFO, "Loguru test");
|
||||
test_thread_names();
|
||||
|
||||
test_scopes();
|
||||
test_levels();
|
||||
#if LOGURU_WITH_STREAMS
|
||||
test_stream();
|
||||
#endif
|
||||
|
||||
loguru::shutdown();
|
||||
|
||||
LOG_F(INFO, "goes to stderr, but not to file");
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string test = argv[1];
|
||||
if (test == "ABORT_F") {
|
||||
ABORT_F("ABORT_F format message");
|
||||
} else if (test == "ABORT_S") {
|
||||
ABORT_S() << "ABORT_S stream message";
|
||||
} else if (test == "assert") {
|
||||
const char* ptr = nullptr;
|
||||
(void)ptr;
|
||||
assert(ptr && "Error that was unexpected");
|
||||
} else if (test == "LOG_F_FATAL") {
|
||||
LOG_F(FATAL, "Fatal format message");
|
||||
} else if (test == "LOG_S_FATAL") {
|
||||
LOG_S(FATAL) << "Fatal stream message";
|
||||
} else if (test == "CHECK_NOTNULL_F") {
|
||||
const char* ptr = nullptr;
|
||||
CHECK_NOTNULL_F(ptr);
|
||||
} else if (test == "CHECK_F") {
|
||||
CHECK_F(1 > 2);
|
||||
} else if (test == "CHECK_EQ_F") {
|
||||
CHECK_EQ_F(always_increasing(), 0);
|
||||
CHECK_EQ_F(always_increasing(), 1);
|
||||
CHECK_EQ_F(always_increasing(), 42);
|
||||
} else if (test == "CHECK_EQ_F_int") {
|
||||
int x = 42;
|
||||
CHECK_EQ_F(x, x + 1);
|
||||
} else if (test == "CHECK_EQ_F_unsigned") {
|
||||
unsigned x = 42;
|
||||
CHECK_EQ_F(x, x + 1);
|
||||
} else if (test == "CHECK_EQ_F_size_t") {
|
||||
size_t x = 42;
|
||||
CHECK_EQ_F(x, x + 1);
|
||||
} else if (test == "CHECK_EQ_F_message") {
|
||||
CHECK_EQ_F(always_increasing(), 0, "Should pass");
|
||||
CHECK_EQ_F(always_increasing(), 1, "Should pass");
|
||||
CHECK_EQ_F(always_increasing(), 42, "Should fail");
|
||||
} else if (test == "CHECK_EQ_S") {
|
||||
std::string str = "right";
|
||||
CHECK_EQ_F(str, "wrong", "Expected to fail, since `str` isn't \"wrong\" but \"%s\"", str.c_str());
|
||||
} else if (test == "CHECK_LT_S") {
|
||||
CHECK_EQ_F(always_increasing(), 0);
|
||||
CHECK_EQ_F(always_increasing(), 1);
|
||||
CHECK_EQ_F(always_increasing(), 42);
|
||||
} else if (test == "CHECK_LT_S_message") {
|
||||
CHECK_EQ_F(always_increasing(), 0, "Should pass");
|
||||
CHECK_EQ_F(always_increasing(), 1, "Should pass");
|
||||
CHECK_EQ_F(always_increasing(), 42, "Should fail!");
|
||||
} else if (test == "deep_abort") {
|
||||
deep_abort_10({"deep_abort"});
|
||||
} else if (test == "SIGSEGV") {
|
||||
test_SIGSEGV_2();
|
||||
} else if (test == "abort") {
|
||||
test_abort_2();
|
||||
} else if (test == "error_context") {
|
||||
test_error_contex();
|
||||
} else if (test == "throw_on_fatal") {
|
||||
throw_on_fatal();
|
||||
} else if (test == "throw_on_signal") {
|
||||
throw_on_signal();
|
||||
} else if (test == "callback") {
|
||||
test_log_callback();
|
||||
} else if (test == "hang") {
|
||||
loguru::add_file("hang.log", loguru::Truncate, loguru::Verbosity_INFO);
|
||||
test_hang_2();
|
||||
} else {
|
||||
LOG_F(ERROR, "Unknown test: '%s'", test.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user