unit test refactoring. g2log, safe to do shutdownlogging multiple times

This commit is contained in:
KjellKod 2013-07-13 19:33:00 -06:00
parent 3e2f092924
commit c015191b83
6 changed files with 450 additions and 508 deletions

View File

@ -77,67 +77,42 @@ IF(UNIX)
set(SRC_PLATFORM_SPECIFIC ${LOG_SRC}/crashhandler_unix.cpp)
ENDIF(UNIX)
if (MSVC)
# VC11 bug: http://code.google.com/p/googletest/issues/detail?id=408
# add_definition(-D_VARIADIC_MAX=10)
# https://github.com/anhstudios/swganh/pull/186/files
ADD_DEFINITIONS (/D_VARIADIC_MAX=10)
MESSAGE(STATUS "- MSVC: Set variadic max to 10 for MSVC compatibility")
# Remember to set set target properties if using GTEST similar to done below on target "unit_test"
# "set_target_properties(unit_test PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
endif ()
#Visual Studio 2010 -- must use justthread. For now hardcoded for x64
IF(MSVC10)
MESSAGE("")
MESSAGE("Windows: Please run the command [cmake -DCMAKE_BUILD_TYPE=Release -G \"Visual Studio 10\" ..]")
MESSAGE("if cmake finishes OK, do 'msbuild g2log_by_kjellkod.sln /p:Configuration=Release'")
MESSAGE("then run 'Release\\g2log-FATAL-example.exe' or whatever performance test you feel like trying")
MESSAGE("")
set(PLATFORM_LINK_LIBRIES $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc10_mdd.lib)
#set(PLATFORM_LINK_LIBRIES $ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/lib/justthread_vc10x64_mdd.lib)
set(SRC_PLATFORM_SPECIFIC ${LOG_SRC}/crashhandler_win.cpp)
include_directories("$ENV{PROGRAMFILES}/JustSoftwareSolutions/JustThread/include")
ENDIF(MSVC10)
# Visual Studio 2011 -- std::thread etc are included with the Visual Studio package, so justthread dependencies are removed
IF(MSVC11)
IF(MSVC)
# VC11 bug: http://code.google.com/p/googletest/issues/detail?id=408
# add_definition(-D_VARIADIC_MAX=10)
# https://github.com/anhstudios/swganh/pull/186/files
ADD_DEFINITIONS (/D_VARIADIC_MAX=10)
MESSAGE(STATUS "- MSVC: Set variadic max to 10 for MSVC compatibility")
# Remember to set set target properties if using GTEST similar to done below on target "unit_test"
# "set_target_properties(unit_test PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
MESSAGE("")
MESSAGE("Windows: Please run the command [cmake -DCMAKE_BUILD_TYPE=Release -G \"Visual Studio 11\" ..]")
MESSAGE("if cmake finishes OK, do 'msbuild g2log_by_kjellkod.sln /p:Configuration=Release'")
MESSAGE("then run 'Release\\g2log-FATAL-example.exe' or whatever performance test you feel like trying")
MESSAGE("")
set(SRC_PLATFORM_SPECIFIC ${LOG_SRC}/crashhandler_win.cpp)
ENDIF(MSVC11)
ENDIF(MSVC)
# GENERIC STEPS
set(CPP_H_FILES g2logworker.cpp g2logworker.h
g2log.cpp g2log.h g2time.cpp g2time.h
g2future.h std2_make_unique.hpp)
FOREACH(file ${CPP_H_FILES})
set(SRC_FILES ${SRC_FILES} ${LOG_SRC}/${file})
ENDFOREACH(file ${CPP_H_FILES})
file(GLOB SRC_FILES ${LOG_SRC}/*.h ${LOG_SRC}/*.hpp ${LOG_SRC}/*.cpp )
if(MSVC)
list(REMOVE_ITEM SRC_FILES ${LOG_SRC}/crashhandler_unix.cpp)
else()
list(REMOVE_ITEM SRC_FILES ${LOG_SRC}/crashhandler_win.cpp)
endif(MSVC)
set(SRC_FILES ${SRC_FILES} ${SRC_PLATFORM_SPECIFIC})
#
# set(SRC_CPP ${LOG_SRC}/g2logworker.cpp ${LOG_SRC}/g2log.cpp ${LOG_SRC}/g2time.cpp)
# set(SRC_H ${LOG_SRC}/g2logworker.h ${LOG_SRC}/g2log.h ${LOG_SRC}/crashhandler.h ${LOG_SRC}/g2time.h ${LOG_SRC}/g2future.h ${LOG_SRC}/std2_make_unique.hpp)
# set(SRC_FILES ${SRC_CPP} ${SRC_H} ${SRC_PLATFORM_SPECIFIC})
# add a ActiveObject library
add_library(lib_activeobject ${LOG_SRC}/active.cpp ${LOG_SRC}/active.h ${LOG_SRC}/shared_queue.h)
set_target_properties(lib_activeobject PROPERTIES LINKER_LANGUAGE CXX)
# add a g2log library
include_directories(src)
# Create the g2log library
include_directories(${LOG_SRC})
MESSAGE(" g2logger files: [${SRC_FILES}]")
add_library(lib_g2logger ${SRC_FILES})
set_target_properties(lib_g2logger PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(lib_g2logger lib_activeobject)
@ -152,21 +127,19 @@ ENDIF(MSVC11)
# before it can be "cmake'd" and compiled --- leaving it as OFF for now
# ============================================================================
# 1. a simple test example 'g2log-FATAL-example'
option (USE_SIMPLE_EXAMPLE
"Create simple binaries that runs a few LOG calls" ON)
option (USE_SIMPLE_EXAMPLE "Simple (fatal-crash) example " ON)
# 2. performance test (average + worst case) for KjellKod's g2log
option (USE_G2LOG_PERFORMANCE
"Create performance tests for g2log" OFF)
option (USE_G2LOG_PERFORMANCE "g2log performance test" OFF)
# 3. performance test for Google's glog
option (USE_GOOGLE_GLOG_PERFORMANCE
"Create performance tests for Google's glog (remember to install glog, snapshot available at g2log/3rdParty/glog)" ON)
# remember to install glog, snapshot available at g2log/3rdParty/glog
option (USE_GOOGLE_GLOG_PERFORMANCE "Google's glog performance test" OFF)
# 4. unit test for g2log
option (USE_G2LOG_UNIT_TEST
"Create unit test for g2log (remember to unzip Google's gtest framework, available at g2log/3rdParty/gtest)" ON)
# remember to unzip gtest at g2log/3rdParty/gtest
option (USE_G2LOG_UNIT_TEST "g2log unit tests" ON)
@ -182,7 +155,7 @@ ENDIF(MSVC11)
MESSAGE(" g2log-FATAL-example option ON")
include_directories (${DIR_EXAMPLE})
add_executable(g2log-FATAL-example ${DIR_EXAMPLE}/main.cpp)
target_link_libraries(g2log-FATAL-example lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
target_link_libraries(g2log-FATAL-example lib_g2logger ${PLATFORM_LINK_LIBRIES})
endif (USE_SIMPLE_EXAMPLE)
@ -197,13 +170,13 @@ ENDIF(MSVC11)
${DIR_PERFORMANCE}/main_threaded_mean.cpp ${DIR_PERFORMANCE}/performance.h)
# Turn on G2LOG performance flag
set_target_properties(g2log-performance-threaded_mean PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
target_link_libraries(g2log-performance-threaded_mean lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
target_link_libraries(g2log-performance-threaded_mean lib_g2logger ${PLATFORM_LINK_LIBRIES})
# WORST CASE PERFORMANCE TEST
add_executable(g2log-performance-threaded_worst ${DIR_PERFORMANCE}/main_threaded_worst.cpp ${DIR_PERFORMANCE}/performance.h)
# Turn on G2LOG performance flag
set_target_properties(g2log-performance-threaded_worst PROPERTIES COMPILE_DEFINITIONS "G2LOG_PERFORMANCE=1")
target_link_libraries(g2log-performance-threaded_worst lib_activeobject lib_g2logger ${PLATFORM_LINK_LIBRIES})
target_link_libraries(g2log-performance-threaded_worst lib_g2logger ${PLATFORM_LINK_LIBRIES})
endif (USE_G2LOG_PERFORMANCE)
@ -216,26 +189,24 @@ ENDIF(MSVC11)
#Linux is easy!
if(UNIX)
set(GLOG_LIB glog)
# create the the GOOGLE MEAN_PERFORMANCE executable
# create the the GOOGLE MEAN_PERFORMANCE executable
add_executable(google_glog-performance-threaded_mean ${DIR_PERFORMANCE}/main_threaded_mean.cpp ${DIR_PERFORMANCE}/performance.h)
set_target_properties(google_glog-performance-threaded_mean PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
target_link_libraries(google_glog-performance-threaded_mean lib_activeobject ${GLOG_LIB} ${PLATFORM_LINK_LIBRIES})
target_link_libraries(google_glog-performance-threaded_mean ${GLOG_LIB} ${PLATFORM_LINK_LIBRIES})
# create the the GOOGLE MEAN_PERFORMANCE executable
add_executable(google_glog-performance-threaded_worst ${DIR_PERFORMANCE}/main_threaded_worst.cpp ${DIR_PERFORMANCE}/performance.h)
set_target_properties(google_glog-performance-threaded_worst PROPERTIES COMPILE_DEFINITIONS "GOOGLE_GLOG_PERFORMANCE=1")
target_link_libraries(google_glog-performance-threaded_worst lib_activeobject ${GLOG_LIB} ${PLATFORM_LINK_LIBRIES})
endif(UNIX)
target_link_libraries(google_glog-performance-threaded_worst ${GLOG_LIB} ${PLATFORM_LINK_LIBRIES})
endif(UNIX)
# GLOG on Linux is easy - but for Windows trickier,. and it doesn't work (as of yet)
# GLOG on Linux is easy - but for Windows trickier,. and it doesn't work (as of yet)
if(WIN32)
MESSAGE("******************************************************")
MESSAGE("*** SORRY- Google glog on windows is not preconfigured")
MESSAGE("*** You have to do this yourself: ref CMakeLists.txt")
MESSAGE("*** SORRY- Google glog on windows is not preconfigured")
MESSAGE("*** You have to do this yourself: ref CMakeLists.txt")
MESSAGE("******************************************************")
MESSAGE("")
#set(GLOG_DIR ../3rdParty/glog/glog-0.3.1)
#include_directories(${GLOG_DIR}/src/windows)
MESSAGE("")
endif(WIN32)
endif (USE_GOOGLE_GLOG_PERFORMANCE)
@ -244,40 +215,48 @@ ENDIF(MSVC11)
# =========================
if (USE_G2LOG_UNIT_TEST)
MESSAGE(" g2log unit testing option ON")
# SETUP for GTEST
set(GTEST_DIR ../3rdParty/gtest/gtest-1.6.0__stripped)
set(GTEST_INCLUDE_DIRECTORIES ${GTEST_DIR}/include ${GTEST_DIR} ${GTEST_DIR}/src)
include_directories(${GTEST_INCLUDE_DIRECTORIES})
add_library(gtest_160_lib ${GTEST_DIR}/src/gtest-all.cc ${GTEST_DIR}/src/gtest_main.cc)
enable_testing(true)
# obs see this: http://stackoverflow.com/questions/9589192/how-do-i-change-the-number-of-template-arguments-supported-by-msvcs-stdtupl
# obs see this: http://stackoverflow.com/questions/9589192/how-do-i-change-the-number-of-template-arguments-supported-by-msvcs-stdtupl
# and this: http://stackoverflow.com/questions/2257464/google-test-and-visual-studio-2010-rc
SET(tests_to_run test_filechange test_io test_configuration test_sink)
SET(helper ${DIR_UNIT_TEST}/testing_helpers.h ${DIR_UNIT_TEST}/testing_helpers.cpp)
FOREACH(test ${tests_to_run} )
# SET(all_tests ${all_tests} ${DIR_UNIT_TEST}/${test}.cpp )
IF(${test} STREQUAL "test_filechange")
add_executable(${test} ${DIR_UNIT_TEST}/${test}.cpp)
ELSE()
add_executable(${test} ../test_main/test_main.cpp ${DIR_UNIT_TEST}/${test}.cpp ${helper})
ENDIF(${test} STREQUAL "test_filechange")
include_directories(${DIR_UNIT_TEST})
FOREACH(test ${tests_to_run} )
SET(all_tests ${all_tests} ${DIR_UNIT_TEST}/${test}.cpp )
IF(${test} STREQUAL "test_filechange")
add_executable(${test} ${DIR_UNIT_TEST}/${test}.cpp ${helper})
ELSE()
add_executable(${test} ../test_main/test_main.cpp ${DIR_UNIT_TEST}/${test}.cpp ${helper})
ENDIF(${test} STREQUAL "test_filechange")
set_target_properties(${test} PROPERTIES COMPILE_DEFINITIONS "_VARIADIC_MAX=10")
set_target_properties(${test} PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
target_link_libraries(${test} lib_activeobject lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
target_link_libraries(${test} lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
ENDFOREACH(test)
add_executable(test_ALL ${all_tests} ${DIR_UNIT_TEST}/test_filechange.cpp ${helper})
set_target_properties(test_ALL PROPERTIES COMPILE_DEFINITIONS "_VARIADIC_MAX=10")
set_target_properties(test_ALL PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
target_link_libraries(test_ALL lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
# add_executable(test_ALL ${all_tests})
#
# set_target_properties(${test_ALL} PROPERTIES COMPILE_DEFINITIONS "_VARIADIC_MAX=10")
# set_target_properties(${test_ALL} PROPERTIES COMPILE_DEFINITIONS "GTEST_USE_OWN_TR1_TUPLE=0")
# target_link_libraries(${test_ALL} lib_activeobject lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
# target_link_libraries(${test_ALL} lib_g2logger gtest_160_lib ${PLATFORM_LINK_LIBRIES})
endif (USE_G2LOG_UNIT_TEST)

View File

@ -74,10 +74,9 @@ void initializeLogging(g2LogWorker *bgworker)
}
}
g2LogWorker* shutDownLogging()
g2LogWorker* shutDownLogging() // safe to call multiple times
{
std::lock_guard<std::mutex> lock(internal::g_logging_init_mutex);
CHECK(internal::isLoggingInitialized());
g2LogWorker *backup = internal::g_logger_instance;
internal::g_logger_instance = nullptr;
return backup;

View File

@ -1,8 +1,8 @@
/** ==========================================================================
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
* 2012 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <gtest/gtest.h>
@ -12,103 +12,64 @@
#include <memory>
#include <future>
#include <queue>
#include <algorithm>
#include <mutex>
#include <thread>
#include "g2log.h"
#include "g2logworker.h"
#include "testing_helpers.h"
using namespace testing_helper__cleaner;
namespace { // anonymous
const char* name_path_1 = "./some_fake_DirectoryOrName_1_";
const char* name_path_2 = "./some_fake_DirectoryOrName_3_";
g2LogWorker* g_logger_ptr = nullptr;
const char* name_path_1 = "./some_fake_DirectoryOrName_1_";
const char* name_path_2 = "./some_fake_DirectoryOrName_3_";
g2LogWorker* g_logger_ptr = nullptr;
LogFileCleaner* g_cleaner_ptr = nullptr;
bool isTextAvailableInContent(const std::string &total_text,std::string msg_to_find)
{
std::string content(total_text);
size_t location = content.find(msg_to_find);
return (location != std::string::npos);
}
std::string readFileToText(std::string filename)
{
std::ifstream in;
in.open(filename.c_str(),std::ios_base::in);
if(!in.is_open())
{
return ""; // error just return empty string - test will 'fault'
}
std::ostringstream oss;
oss << in.rdbuf();
std::string content(oss.str());
return content;
}
bool removeFile(std::string path_to_file)
{
return (0 == std::remove(path_to_file.c_str()));
}
class LogFileCleaner // RAII cluttering files cleanup
{
private:
std::vector<std::string> logs_to_clean_;
std::mutex g_mutex;
public:
size_t size(){return logs_to_clean_.size();}
virtual ~LogFileCleaner() {
std::lock_guard<std::mutex> lock(g_mutex);
{
for (std::string p : logs_to_clean_)
{
if(false == removeFile(p))
{
ADD_FAILURE() << "UNABLE to remove: " << p.c_str() << std::endl;
}
}
logs_to_clean_.clear();
} // mutex
bool isTextAvailableInContent(const std::string &total_text, std::string msg_to_find) {
std::string content(total_text);
size_t location = content.find(msg_to_find);
return (location != std::string::npos);
}
void addLogToClean(std::string path_to_log) {
std::lock_guard<std::mutex> lock(g_mutex);
std::string readFileToText(std::string filename) {
std::ifstream in;
in.open(filename.c_str(), std::ios_base::in);
if (!in.is_open()) {
return ""; // error just return empty string - test will 'fault'
}
std::ostringstream oss;
oss << in.rdbuf();
std::string content(oss.str());
return content;
}
std::string changeDirectoryOrName(std::string new_file_to_create) {
static std::mutex m;
static int count;
std::lock_guard<std::mutex> lock(m);
{
if (std::find(logs_to_clean_.begin(), logs_to_clean_.end(), path_to_log.c_str()) == logs_to_clean_.end())
logs_to_clean_.push_back(path_to_log);
std::string add_count = std::to_string(++count) + "_";
auto new_log = g_logger_ptr->changeLogFile(new_file_to_create + add_count).get();
if (!new_log.empty()) g_cleaner_ptr->addLogToClean(new_log);
return new_log;
}
}
}; LogFileCleaner* g_cleaner_ptr = nullptr;
std::string changeDirectoryOrName(std::string new_file_to_create)
{
static std::mutex m;
static int count;
std::lock_guard<std::mutex> lock(m);
{
std::string add_count = std::to_string(++count) + "_";
auto new_log = g_logger_ptr->changeLogFile(new_file_to_create+add_count).get();
if(!new_log.empty()) g_cleaner_ptr->addLogToClean(new_log);
return new_log;
}
}
} // anonymous
// TODO: this must change. Initialization of this is done here! and not in a special test_main.cpp
// which MAY be OK ... however it is also very redundant with test_io
TEST(TestOf_GetFileName, Expecting_ValidLogFile)
{
TEST(TestOf_GetFileName, Expecting_ValidLogFile) {
LOG(INFO) << "test_filechange, Retrieving file name: ";
ASSERT_NE(g_logger_ptr, nullptr);
@ -117,42 +78,33 @@ TEST(TestOf_GetFileName, Expecting_ValidLogFile)
ASSERT_FALSE(f_get_old_name.get().empty());
}
TEST(TestOf_ChangingLogFile, Expecting_NewLogFileUsed)
{
TEST(TestOf_ChangingLogFile, Expecting_NewLogFileUsed) {
auto old_log = g_logger_ptr->logFileName().get();
std::string name = changeDirectoryOrName(name_path_1);
auto new_log = g_logger_ptr->changeLogFile(name).get();
}
TEST(TestOf_ManyThreadsChangingLogFileName, Expecting_EqualNumberLogsCreated)
{
TEST(TestOf_ManyThreadsChangingLogFileName, Expecting_EqualNumberLogsCreated) {
auto old_log = g_logger_ptr->logFileName().get();
if(!old_log.empty()) g_cleaner_ptr->addLogToClean(old_log);
if (!old_log.empty()) g_cleaner_ptr->addLogToClean(old_log);
LOG(INFO) << "SoManyThreadsAllDoingChangeFileName";
std::vector<std::thread> threads;
auto max = 2;
auto size = g_cleaner_ptr->size();
for(auto count = 0; count < max; ++count)
{
for (auto count = 0; count < max; ++count) {
std::string drive = ((count % 2) == 0) ? "./_threadEven_" : "./_threaOdd_";
threads.push_back(std::thread(changeDirectoryOrName, drive));
}
for(auto& thread : threads)
for (auto& thread : threads)
thread.join();
// check that all logs were created
ASSERT_EQ(size+max, g_cleaner_ptr->size());
ASSERT_EQ(size + max, g_cleaner_ptr->size());
}
TEST(TestOf_IllegalLogFileName, Expecting_NoChangeToOriginalFileName)
{
std::string original = g_logger_ptr->logFileName().get();
TEST(TestOf_IllegalLogFileName, Expecting_NoChangeToOriginalFileName) {
std::string original = g_logger_ptr->logFileName().get();
std::cerr << "Below WILL print 'FiLE ERROR'. This is part of the testing and perfectly OK" << std::endl;
std::cerr << "****" << std::endl;
std::future<std::string> perhaps_a_name = g_logger_ptr->changeLogFile("XY:/"); // does not exist
@ -162,11 +114,7 @@ TEST(TestOf_IllegalLogFileName, Expecting_NoChangeToOriginalFileName)
ASSERT_STREQ(original.c_str(), post_illegal.c_str());
}
int main(int argc, char *argv[])
{
int main(int argc, char *argv[]) {
LogFileCleaner cleaner;
g_cleaner_ptr = &cleaner;
int return_value = 1;
@ -180,7 +128,7 @@ int main(int argc, char *argv[])
cleaner.addLogToClean(g_logger_ptr->logFileName().get());
return_value = RUN_ALL_TESTS();
last_log_file = g_logger_ptr->logFileName().get();
g2::shutDownLogging();
//g2::shutDownLogging();
}
std::cout << "FINISHED WITH THE TESTING" << std::endl;
// cleaning up

View File

@ -1,8 +1,8 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
* ============================================================================*/
#include <gtest/gtest.h>
#include "g2log.h"
@ -13,33 +13,30 @@
#include <string>
#include <fstream>
#include <cstdio>
#include <thread>
#include <chrono>
namespace {
const int k_wait_time = 5; // 5s wait between LOG/CHECK FATAL till we say it's too long time
const std::string log_directory = "./";
namespace
{
const int k_wait_time = 5; // 5s wait between LOG/CHECK FATAL till we say it's too long time
const std::string log_directory = "./";
bool verifyContent(const std::string &total_text, std::string msg_to_find) {
std::string content(total_text);
size_t location = content.find(msg_to_find);
return (location != std::string::npos);
}
bool verifyContent(const std::string &total_text,std::string msg_to_find)
{
std::string content(total_text);
size_t location = content.find(msg_to_find);
return (location != std::string::npos);
}
std::string readFileToText(std::string filename)
{
std::ifstream in;
in.open(filename.c_str(),std::ios_base::in);
if(!in.is_open())
{
return ""; // error just return empty string - test will 'fault'
}
std::ostringstream oss;
oss << in.rdbuf();
std::string content(oss.str());
return content;
}
std::string readFileToText(std::string filename) {
std::ifstream in;
in.open(filename.c_str(), std::ios_base::in);
if (!in.is_open()) {
return ""; // error just return empty string - test will 'fault'
}
std::ostringstream oss;
oss << in.rdbuf();
std::string content(oss.str());
return content;
}
} // end anonymous namespace
@ -49,324 +46,273 @@ namespace
// LOG
TEST(LOGTest, LOG)
TEST(IO_RestoreLogger, Expecting_Fine_To_ShutDownMultipleTimes)
{
std::string file_content;
{
RestoreLogger logger(log_directory);
LOG(INFO) << "test LOG(INFO)";
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, "test LOG(INFO)"));
RestoreLogger logger1("");
std::this_thread::sleep_for( std::chrono::milliseconds(1000));
RestoreLogger logger2("./");
}
namespace {
const std::string t_info = "test INFO ";
const std::string t_info2 = "test INFO 123";
const std::string t_debug = "test DEBUG ";
const std::string t_debug2 = "test DEBUG 1.123456";
const std::string t_warning = "test WARNING ";
const std::string t_warning2 = "test WARNING yello";
TEST(LOGTest, LOG) {
std::string file_content;
{
RestoreLogger logger(log_directory);
LOG(INFO) << "test LOG(INFO)";
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, "test LOG(INFO)"));
}
namespace {
const std::string t_info = "test INFO ";
const std::string t_info2 = "test INFO 123";
const std::string t_debug = "test DEBUG ";
const std::string t_debug2 = "test DEBUG 1.123456";
const std::string t_warning = "test WARNING ";
const std::string t_warning2 = "test WARNING yello";
}
// printf-type log
TEST(LogTest, LOG_F)
{
std::string file_content;
{
RestoreLogger logger(log_directory);
std::cout << "logfilename: " << logger.logFile() << std::flush << std::endl;
LOGF(INFO, std::string(t_info + "%d").c_str(), 123);
LOGF(DEBUG, std::string(t_debug + "%f").c_str(), 1.123456);
LOGF(WARNING, std::string(t_warning + "%s").c_str(), "yello");
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_TRUE(verifyContent(file_content, t_debug2));
ASSERT_TRUE(verifyContent(file_content, t_warning2));
TEST(LogTest, LOG_F) {
std::string file_content;
{
RestoreLogger logger(log_directory);
std::cout << "logfilename: " << logger.logFile() << std::flush << std::endl;
LOGF(INFO, std::string(t_info + "%d").c_str(), 123);
LOGF(DEBUG, std::string(t_debug + "%f").c_str(), 1.123456);
LOGF(WARNING, std::string(t_warning + "%s").c_str(), "yello");
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_TRUE(verifyContent(file_content, t_debug2));
ASSERT_TRUE(verifyContent(file_content, t_warning2));
}
// stream-type log
TEST(LogTest, LOG)
{
std::string file_content;
{
RestoreLogger logger(log_directory);
LOG(INFO) << t_info << 123;
LOG(DEBUG) << t_debug << std::setprecision(7) << 1.123456f;
LOG(WARNING) << t_warning << "yello";
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_TRUE(verifyContent(file_content, t_debug2));
ASSERT_TRUE(verifyContent(file_content, t_warning2));
TEST(LogTest, LOG) {
std::string file_content;
{
RestoreLogger logger(log_directory);
LOG(INFO) << t_info << 123;
LOG(DEBUG) << t_debug << std::setprecision(7) << 1.123456f;
LOG(WARNING) << t_warning << "yello";
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_INFO"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_TRUE(verifyContent(file_content, t_debug2));
ASSERT_TRUE(verifyContent(file_content, t_warning2));
}
TEST(LogTest, LOG_F_IF)
{
std::string file_content;
{
RestoreLogger logger(log_directory);
LOGF_IF(INFO, (2 == 2), std::string(t_info + "%d").c_str(), 123);
LOGF_IF(DEBUG, (2 != 2), std::string(t_debug + "%f").c_str(), 1.123456);
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_IF"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_FALSE(verifyContent(file_content, t_debug2));
TEST(LogTest, LOG_F_IF) {
std::string file_content;
{
RestoreLogger logger(log_directory);
LOGF_IF(INFO, (2 == 2), std::string(t_info + "%d").c_str(), 123);
LOGF_IF(DEBUG, (2 != 2), std::string(t_debug + "%f").c_str(), 1.123456);
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_IF"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_FALSE(verifyContent(file_content, t_debug2));
}
TEST(LogTest, LOG_IF)
{
std::string file_content;
{
RestoreLogger logger(log_directory);
LOG_IF(INFO, (2 == 2)) << t_info << 123;
LOG_IF(DEBUG, (2 != 2)) << t_debug << std::setprecision(7) << 1.123456f;
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_IF"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_FALSE(verifyContent(file_content, t_debug2));
TEST(LogTest, LOG_IF) {
std::string file_content;
{
RestoreLogger logger(log_directory);
LOG_IF(INFO, (2 == 2)) << t_info << 123;
LOG_IF(DEBUG, (2 != 2)) << t_debug << std::setprecision(7) << 1.123456f;
logger.reset(); // force flush of logger
file_content = readFileToText(logger.logFile());
SCOPED_TRACE("LOG_IF"); // Scope exit be prepared for destructor failure
}
ASSERT_TRUE(verifyContent(file_content, t_info2));
ASSERT_FALSE(verifyContent(file_content, t_debug2));
}
TEST(LogTest, LOGF__FATAL)
{
RestoreLogger logger(log_directory);
try
{
LOGF(FATAL, "This message should throw %d",0);
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
std::cerr << file_content << std::endl << std::flush;
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw"))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
TEST(LogTest, LOGF__FATAL) {
RestoreLogger logger(log_directory);
try {
LOGF(FATAL, "This message should throw %d", 0);
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
std::cerr << file_content << std::endl << std::flush;
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw")) {
SUCCEED();
return;
} else {
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOG_FATAL)
{
RestoreLogger logger(log_directory);
try
{
LOG(FATAL) << "This message should throw";
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw"))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
TEST(LogTest, LOG_FATAL) {
RestoreLogger logger(log_directory);
try {
LOG(FATAL) << "This message should throw";
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw")) {
SUCCEED();
return;
} else {
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOGF_IF__FATAL)
{
RestoreLogger logger(log_directory);
try
{
LOGF_IF(FATAL, (2<3), "This message%sshould throw"," ");
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw"))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
TEST(LogTest, LOGF_IF__FATAL) {
RestoreLogger logger(log_directory);
try {
LOGF_IF(FATAL, (2 < 3), "This message%sshould throw", " ");
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw")) {
SUCCEED();
return;
} else {
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOG_IF__FATAL)
{
RestoreLogger logger(log_directory);
try
{
LOG_IF(WARNING, (0 != t_info.compare(t_info))) << "This message should NOT be written";
LOG_IF(FATAL, (0 != t_info.compare(t_info2))) << "This message should throw";
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw") &&
(false == verifyContent(file_content, "This message should NOT be written")))
{
SUCCEED();
return;
}
else
{
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
TEST(LogTest, LOG_IF__FATAL) {
RestoreLogger logger(log_directory);
try {
LOG_IF(WARNING, (0 != t_info.compare(t_info))) << "This message should NOT be written";
LOG_IF(FATAL, (0 != t_info.compare(t_info2))) << "This message should throw";
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, "This message should throw") &&
(false == verifyContent(file_content, "This message should NOT be written"))) {
SUCCEED();
return;
} else {
ADD_FAILURE() << "Didn't throw exception as expected";
}
}
ADD_FAILURE() << "Didn't throw exception at ALL";
}
TEST(LogTest, LOG_IF__FATAL__NO_THROW)
{
RestoreLogger logger(log_directory);
try
{
LOG_IF(FATAL, (2>3)) << "This message%sshould NOT throw";
}
catch (std::exception const &e)
{
std::cerr << e.what() << std::endl;
logger.reset();
ADD_FAILURE() << "Didn't throw exception as expected";
}
logger.reset();
SUCCEED();
TEST(LogTest, LOG_IF__FATAL__NO_THROW) {
RestoreLogger logger(log_directory);
try {
LOG_IF(FATAL, (2 > 3)) << "This message%sshould NOT throw";
} catch (std::exception const &e) {
std::cerr << e.what() << std::endl;
logger.reset();
ADD_FAILURE() << "Didn't throw exception as expected";
}
logger.reset();
SUCCEED();
}
// CHECK_F
TEST(CheckTest, CHECK_F__thisWILL_PrintErrorMsg)
{
RestoreLogger logger(log_directory);
try
{
CHECK(1 == 2);
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL"))
{
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
TEST(CheckTest, CHECK_F__thisWILL_PrintErrorMsg) {
RestoreLogger logger(log_directory);
try {
CHECK(1 == 2);
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL")) {
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
}
TEST(CHECK_F_Test, CHECK_F__thisWILL_PrintErrorMsg)
{
RestoreLogger logger(log_directory);
std::string msg = "This message is added to throw %s and %s";
std::string msg2 = "This message is added to throw message and log";
std::string arg1 = "message";
std::string arg2 = "log";
try
{
CHECK_F(1 >= 2, msg.c_str(), arg1.c_str(), arg2.c_str());
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, msg2))
{
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
TEST(CHECK_F_Test, CHECK_F__thisWILL_PrintErrorMsg) {
RestoreLogger logger(log_directory);
std::string msg = "This message is added to throw %s and %s";
std::string msg2 = "This message is added to throw message and log";
std::string arg1 = "message";
std::string arg2 = "log";
try {
CHECK_F(1 >= 2, msg.c_str(), arg1.c_str(), arg2.c_str());
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, msg2)) {
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
}
TEST(CHECK_Test, CHECK__thisWILL_PrintErrorMsg)
{
RestoreLogger logger(log_directory);
std::string msg = "This message is added to throw %s and %s";
std::string msg2 = "This message is added to throw message and log";
std::string arg1 = "message";
std::string arg2 = "log";
try
{
CHECK(1 >= 2) << msg2;
}
catch (std::exception const &e)
{
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if(verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, msg2))
{
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
TEST(CHECK_Test, CHECK__thisWILL_PrintErrorMsg) {
RestoreLogger logger(log_directory);
std::string msg = "This message is added to throw %s and %s";
std::string msg2 = "This message is added to throw message and log";
std::string arg1 = "message";
std::string arg2 = "log";
try {
CHECK(1 >= 2) << msg2;
} catch (std::exception const &e) {
logger.reset();
std::string file_content = readFileToText(logger.logFile());
if (verifyContent(e.what(), "EXIT trigger caused by ") &&
verifyContent(file_content, "FATAL") &&
verifyContent(file_content, msg2)) {
SUCCEED();
return;
}
}
ADD_FAILURE() << "Didn't throw exception as expected";
}
TEST(CHECK, CHECK_ThatWontThrow) {
RestoreLogger logger(log_directory);
std::string msg = "This %s should never appear in the %s";
std::string msg2 = "This message should never appear in the log";
std::string arg1 = "message";
std::string arg2 = "log";
try {
CHECK(1 == 1);
CHECK_F(1 == 1, msg.c_str(), "message", "log");
} catch (std::exception const &e) {
std::cerr << e.what() << std::endl;
ADD_FAILURE() << "Should never have thrown";
}
TEST(CHECK, CHECK_ThatWontThrow)
{
RestoreLogger logger(log_directory);
std::string msg = "This %s should never appear in the %s";
std::string msg2 = "This message should never appear in the log";
std::string arg1 = "message";
std::string arg2 = "log";
try
{
CHECK(1 == 1);
CHECK_F(1==1, msg.c_str(), "message", "log");
}
catch (std::exception const &e)
{
std::cerr << e.what() << std::endl;
ADD_FAILURE() << "Should never have thrown";
}
std::string file_content = readFileToText(logger.logFile());
ASSERT_FALSE(verifyContent(file_content, msg2));
std::string file_content = readFileToText(logger.logFile());
ASSERT_FALSE(verifyContent(file_content, msg2));
}

View File

@ -3,18 +3,26 @@
#include "testing_helpers.h"
#include "g2log.h"
#include "g2logworker.h"
#include "std2_make_unique.hpp"
using namespace std;
namespace {
g2LogWorker* oldworker = nullptr;
}
ScopedCout::ScopedCout(std::stringstream* buffer)
: _old_cout(std::cout.rdbuf()) {
cout.rdbuf(buffer->rdbuf());
}
ScopedCout::~ScopedCout() { cout.rdbuf(_old_cout);}
ScopedCout::~ScopedCout() {
cout.rdbuf(_old_cout);
}
RestoreLogger::RestoreLogger(std::string directory)
: logger_(new g2LogWorker("UNIT_TEST_LOGGER", directory)) {
: logger_(std2::make_unique<g2LogWorker>("UNIT_TEST_LOGGER", directory)) {
oldworker = g2::shutDownLogging();
g2::initializeLogging(logger_.get());
g2::internal::changeFatalInitHandlerForUnitTesting();
@ -26,6 +34,7 @@ RestoreLogger::RestoreLogger(std::string directory)
RestoreLogger::~RestoreLogger() {
reset();
g2::shutDownLogging();
if (nullptr != oldworker) g2::initializeLogging(oldworker);
if (0 != remove(log_file_.c_str()))
ADD_FAILURE();
}
@ -33,3 +42,38 @@ RestoreLogger::~RestoreLogger() {
void RestoreLogger::reset() {
logger_.reset();
}
namespace testing_helper__cleaner {
bool removeFile(std::string path_to_file) {
return (0 == std::remove(path_to_file.c_str()));
}
}
size_t LogFileCleaner::size() {
return logs_to_clean_.size();
}
LogFileCleaner::~LogFileCleaner() {
std::lock_guard<std::mutex> lock(g_mutex);
{
for (std::string p : logs_to_clean_) {
if (false == testing_helper__cleaner::removeFile(p)) {
ADD_FAILURE() << "UNABLE to remove: " << p.c_str() << std::endl;
}
}
logs_to_clean_.clear();
} // mutex
}
void LogFileCleaner::addLogToClean(std::string path_to_log) {
std::lock_guard<std::mutex> lock(g_mutex);
{
if (std::find(logs_to_clean_.begin(), logs_to_clean_.end(), path_to_log.c_str()) == logs_to_clean_.end())
logs_to_clean_.push_back(path_to_log);
}
}

View File

@ -11,6 +11,8 @@
#include <memory>
#include <string>
#include <iostream>
#include <mutex>
#include <algorithm>
class g2LogWorker;
@ -20,30 +22,54 @@ class g2LogWorker;
// ScopedCout guard(&buffer);
// cout << "Hello World";
// ASSERT_STREQ(buffer.str().c_str(), "Hello World");
class ScopedCout
class ScopedCout {
std::streambuf* _old_cout;
public:
explicit ScopedCout(std::stringstream* buffer);
~ScopedCout();
};
namespace testing_helper__cleaner {
bool removeFile(std::string path_to_file);
}
class LogFileCleaner // RAII cluttering files cleanup
{
std::streambuf* _old_cout;
public:
explicit ScopedCout(std::stringstream* buffer);
~ScopedCout();
private:
std::vector<std::string> logs_to_clean_;
std::mutex g_mutex;
public:
size_t size();
LogFileCleaner() {
}
virtual ~LogFileCleaner();
void addLogToClean(std::string path_to_log);
};
// RAII temporarily replace of logger
// and restoration of original logger at scope end
struct RestoreLogger
{
explicit RestoreLogger(std::string directory);
~RestoreLogger();
void reset();
std::unique_ptr<g2LogWorker> logger_;
std::string logFile(){return log_file_;}
struct RestoreLogger {
explicit RestoreLogger(std::string directory);
~RestoreLogger();
void reset();
std::unique_ptr<g2LogWorker> logger_;
std::string logFile() {
return log_file_;
}
private:
std::string log_file_;
std::string log_file_;
};
#endif /* TEST_HELPER__RESTORE_LOGGER_H */