mirror of
https://github.com/KjellKod/g3log.git
synced 2025-02-24 23:34:48 +01:00
Generic cleanup and bugfix after massive merge... still ongoing
--HG-- rename : g2log/test_unit/test_sink.cpp => g2log/test_unit/test_sink_concept.cpp
This commit is contained in:
parent
17cf2ee910
commit
d254879890
4
.hgignore
Normal file
4
.hgignore
Normal file
@ -0,0 +1,4 @@
|
||||
syntax: glob
|
||||
g2log-sinks/*
|
||||
3rdParty/*
|
||||
g2log/build/*
|
@ -127,7 +127,7 @@ ENDIF(MSVC)
|
||||
# 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 "Simple (fatal-crash) example " OFF)
|
||||
option (USE_SIMPLE_EXAMPLE "Simple (fatal-crash) example " ON)
|
||||
|
||||
# 2. performance test (average + worst case) for KjellKod's g2log
|
||||
option (USE_G2LOG_PERFORMANCE "g2log performance test" OFF)
|
||||
@ -225,7 +225,7 @@ ENDIF(MSVC)
|
||||
# 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(tests_to_run test_filechange test_io test_configuration test_sink_concept test_sink)
|
||||
SET(helper ${DIR_UNIT_TEST}/testing_helpers.h ${DIR_UNIT_TEST}/testing_helpers.cpp)
|
||||
include_directories(${DIR_UNIT_TEST})
|
||||
|
||||
|
@ -152,7 +152,7 @@ std::string signalName(int signal_number)
|
||||
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
|
||||
void exitWithDefaultSignalHandler(int signal_number)
|
||||
{
|
||||
std::cerr << "Exiting - FATAL SIGNAL: " << signal_number << " " << std::flush;
|
||||
std::cerr << "\nExiting - FATAL SIGNAL: " << signal_number << " " << std::flush;
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(action)); //
|
||||
sigemptyset(&action.sa_mask);
|
||||
|
124
g2log/src/g2filesinkhelper.ipp
Normal file
124
g2log/src/g2filesinkhelper.ipp
Normal file
@ -0,0 +1,124 @@
|
||||
#ifndef G2_FILESINK_HELPER_IPP_
|
||||
#define G2_FILESINK_HELPER_IPP_
|
||||
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
//#include <fstream>
|
||||
//#include <algorithm>
|
||||
//#include <future>
|
||||
//#include <cassert>
|
||||
//#include <chrono>
|
||||
|
||||
|
||||
namespace g2 {
|
||||
namespace internal {
|
||||
|
||||
|
||||
static const std::string file_name_time_formatted = "%Y%m%d-%H%M%S";
|
||||
|
||||
// check for filename validity - filename should not be part of PATH
|
||||
|
||||
bool isValidFilename(const std::string& prefix_filename) {
|
||||
std::string illegal_characters("/,|<>:#$%{}()[]\'\"^!?+* ");
|
||||
size_t pos = prefix_filename.find_first_of(illegal_characters, 0);
|
||||
if (pos != std::string::npos) {
|
||||
std::cerr << "Illegal character [" << prefix_filename.at(pos) << "] in logname prefix: " << "[" << prefix_filename << "]" << std::endl;
|
||||
return false;
|
||||
} else if (prefix_filename.empty()) {
|
||||
std::cerr << "Empty filename prefix is not allowed" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string prefixSanityFix(std::string prefix) {
|
||||
prefix.erase(std::remove_if(prefix.begin(), prefix.end(), ::isspace), prefix.end());
|
||||
prefix.erase(std::remove(prefix.begin(), prefix.end(), '/'), prefix.end());
|
||||
prefix.erase(std::remove(prefix.begin(), prefix.end(), '\\'), prefix.end());
|
||||
prefix.erase(std::remove(prefix.begin(), prefix.end(), '.'), prefix.end());
|
||||
if (!isValidFilename(prefix)) {
|
||||
return
|
||||
{
|
||||
};
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
|
||||
std::string pathSanityFix(std::string path, std::string file_name) {
|
||||
// Unify the delimeters,. maybe sketchy solution but it seems to work
|
||||
// on at least win7 + ubuntu. All bets are off for older windows
|
||||
std::replace(path.begin(), path.end(), '\\', '/');
|
||||
|
||||
// clean up in case of multiples
|
||||
auto contains_end = [&](std::string & in) -> bool {
|
||||
size_t size = in.size();
|
||||
if (!size) return false;
|
||||
char end = in[size - 1];
|
||||
return (end == '/' || end == ' ');
|
||||
};
|
||||
|
||||
while (contains_end(path)) {
|
||||
path.erase(path.size() - 1);
|
||||
}
|
||||
|
||||
if (!path.empty()) {
|
||||
path.insert(path.end(), '/');
|
||||
}
|
||||
|
||||
path.insert(path.size(), file_name);
|
||||
return path;
|
||||
}
|
||||
|
||||
std::string header() {
|
||||
std::ostringstream ss_entry;
|
||||
// Day Month Date Time Year: is written as "%a %b %d %H:%M:%S %Y" and formatted output as : Wed Sep 19 08:28:16 2012
|
||||
ss_entry << "\t\tg2log created log file at: " << g2::localtime_formatted(g2::systemtime_now(), "%a %b %d %H:%M:%S %Y") << "\n";
|
||||
ss_entry << "\t\tLOG format: [YYYY/MM/DD hh:mm:ss.uuu* LEVEL FILE:LINE] message\n\n"; // TODO: if(header)
|
||||
return ss_entry.str();
|
||||
}
|
||||
|
||||
std::string createLogFileName(const std::string& verified_prefix) {
|
||||
std::stringstream oss_name;
|
||||
oss_name << verified_prefix << ".g2log.";
|
||||
oss_name << g2::localtime_formatted(g2::systemtime_now(), file_name_time_formatted);
|
||||
oss_name << ".log";
|
||||
return oss_name.str();
|
||||
}
|
||||
|
||||
bool openLogFile(const std::string& complete_file_with_path, std::ofstream& outstream) {
|
||||
std::ios_base::openmode mode = std::ios_base::out; // for clarity: it's really overkill since it's an ofstream
|
||||
mode |= std::ios_base::trunc;
|
||||
outstream.open(complete_file_with_path, mode);
|
||||
if (!outstream.is_open()) {
|
||||
std::ostringstream ss_error;
|
||||
ss_error << "FILE ERROR: could not open log file:[" << complete_file_with_path << "]";
|
||||
ss_error << "\n\t\t std::ios_base state = " << outstream.rdstate();
|
||||
std::cerr << ss_error.str().c_str() << std::endl;
|
||||
outstream.close();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<std::ofstream> createLogFile(const std::string& file_with_full_path) {
|
||||
std::unique_ptr<std::ofstream> out(new std::ofstream);
|
||||
std::ofstream & stream(*(out.get()));
|
||||
bool success_with_open_file = openLogFile(file_with_full_path, stream);
|
||||
if (false == success_with_open_file) {
|
||||
out.release();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif // G2_FILESINK_HELPER_IPP_
|
@ -43,10 +43,16 @@ int main(int argc, char** argv)
|
||||
double pi_d = 3.1415926535897932384626433832795;
|
||||
float pi_f = 3.1415926535897932384626433832795f;
|
||||
|
||||
|
||||
g2LogWorker logger(argv[0], path_to_log_file);
|
||||
g2::initializeLogging(&logger);
|
||||
std::future<std::string> log_file_name = logger.logFileName();
|
||||
|
||||
// auto logger = g2LogWorker::createWithNoSink();
|
||||
// auto sinkptr = std2::make_unique<g2::g2FileSink>(argv[0], path_to_log_file);
|
||||
// auto log_handle = logger->addSink(std::move(singkptr), &g2::g2FileSink::fileWrite);
|
||||
// g2::initializeLogging(logger.get());
|
||||
auto logger_n_handle = g2LogWorker::createWithDefaultFileSink(argv[0], path_to_log_file);
|
||||
g2::initializeLogging(logger_n_handle.first.get());
|
||||
|
||||
|
||||
std::future<std::string> log_file_name = logger_n_handle.second->call(&g2::g2FileSink::fileName);
|
||||
std::cout << "*** This is an example of g2log " << std::endl;
|
||||
std::cout << "*** It WILL exit by a FATAL trigger in the end" << std::endl;
|
||||
std::cout << "*** Please see the generated log and compare to " << std::endl;
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "g2logworker.h"
|
||||
#include "testing_helpers.h"
|
||||
|
||||
using namespace testing_helper__cleaner;
|
||||
using namespace testing_helpers;
|
||||
|
||||
|
||||
namespace { // anonymous
|
||||
@ -28,9 +28,7 @@ namespace { // anonymous
|
||||
g2LogWorker* g_logger_ptr = nullptr;
|
||||
g2::SinkHandle<g2::g2FileSink>* g_filesink_handler = 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);
|
||||
@ -64,20 +62,19 @@ namespace { // anonymous
|
||||
return add_count;
|
||||
}
|
||||
|
||||
std::string setLogName(std::string new_file_to_create) {
|
||||
std::string setLogName(std::string new_file_to_create) {
|
||||
auto future_new_log = g_filesink_handler->call(&g2::g2FileSink::changeLogFile, new_file_to_create);
|
||||
auto new_log = future_new_log.get();
|
||||
if (!new_log.empty()) g_cleaner_ptr->addLogToClean(new_log);
|
||||
return new_log;
|
||||
}
|
||||
|
||||
|
||||
std::string getLogName() {
|
||||
return g_filesink_handler->call(&g2::g2FileSink::fileName).get();
|
||||
return g_filesink_handler->call(&g2::g2FileSink::fileName).get();
|
||||
}
|
||||
|
||||
} // anonymous
|
||||
|
||||
|
||||
TEST(TestOf_GetFileName, Expecting_ValidLogFile) {
|
||||
|
||||
LOG(INFO) << "test_filechange, Retrieving file name: ";
|
||||
@ -86,14 +83,14 @@ TEST(TestOf_GetFileName, Expecting_ValidLogFile) {
|
||||
}
|
||||
|
||||
TEST(TestOf_ChangingLogFile, Expecting_NewLogFileUsed) {
|
||||
auto old_log = g_filesink_handler->call(&g2::g2FileSink::fileName).get();
|
||||
auto old_log = getLogName();
|
||||
std::string name = setLogNameAndAddCount(name_path_1);
|
||||
auto new_log = setLogName(name);
|
||||
ASSERT_NE(old_log, new_log);
|
||||
}
|
||||
|
||||
TEST(TestOf_ManyThreadsChangingLogFileName, Expecting_EqualNumberLogsCreated) {
|
||||
auto old_log = g_filesink_handler->call(&g2::g2FileSink::fileName).get();
|
||||
auto old_log = g_filesink_handler->call(&g2::g2FileSink::fileName).get();
|
||||
if (!old_log.empty()) g_cleaner_ptr->addLogToClean(old_log);
|
||||
|
||||
LOG(INFO) << "SoManyThreadsAllDoingChangeFileName";
|
||||
@ -113,32 +110,36 @@ TEST(TestOf_ManyThreadsChangingLogFileName, Expecting_EqualNumberLogsCreated) {
|
||||
|
||||
TEST(TestOf_IllegalLogFileName, Expecting_NoChangeToOriginalFileName) {
|
||||
std::string original = getLogName();
|
||||
std::cerr << "Below WILL print 'FiLE ERROR'. This is part of the testing and perfectly OK" << std::endl;
|
||||
std::cerr << "****" << std::endl;
|
||||
auto perhaps_a_name = setLogName("XY:/"); // does not exist
|
||||
ASSERT_TRUE(perhaps_a_name.empty());
|
||||
std::cerr << "****" << std::endl;
|
||||
std::string post_illegal = getLogName();
|
||||
ASSERT_STREQ(original.c_str(), post_illegal.c_str());
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
LogFileCleaner cleaner;
|
||||
g_cleaner_ptr = &cleaner;
|
||||
int return_value = 1;
|
||||
|
||||
std::stringstream cerrDump;
|
||||
|
||||
std::string last_log_file;
|
||||
{
|
||||
auto pair = g2LogWorker::createWithDefaultFileSink("ReplaceLogFile", name_path_2);
|
||||
|
||||
testing_helpers::ScopedOut scopedCerr(std::cerr, &cerrDump);
|
||||
|
||||
auto pair = g2LogWorker::createWithDefaultFileSink("ReplaceLogFile", name_path_1);
|
||||
//g2LogWorker logger("ReplaceLogFile", name_path_2);
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
g_logger_ptr = pair.first.get(); // ugly but fine for this test
|
||||
g_filesink_handler = pair.second.get();
|
||||
|
||||
g2::initializeLogging(g_logger_ptr);
|
||||
cleaner.addLogToClean(g_filesink_handler->call(&g2::g2FileSink::fileName).get());
|
||||
LOG(INFO) << "test_filechange demo*" << std::endl;
|
||||
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return_value = RUN_ALL_TESTS();
|
||||
|
||||
last_log_file = g_filesink_handler->call(&g2::g2FileSink::fileName).get();
|
||||
std::cout << "log file at: " << last_log_file << std::endl;
|
||||
//g2::shutDownLogging();
|
||||
}
|
||||
std::cout << "FINISHED WITH THE TESTING" << std::endl;
|
||||
|
@ -30,21 +30,17 @@ namespace {
|
||||
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'
|
||||
return {}; // error just return empty string - test will 'fault'
|
||||
}
|
||||
std::ostringstream oss;
|
||||
oss << in.rdbuf();
|
||||
std::string content(oss.str());
|
||||
return content;
|
||||
return oss.str();
|
||||
}
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
using namespace testing_helpers;
|
||||
// LOG
|
||||
TEST(IO_RestoreLogger, Expecting_Fine_To_ShutDownMultipleTimes)
|
||||
{
|
||||
|
142
g2log/test_unit/test_sink_concept.cpp
Normal file
142
g2log/test_unit/test_sink_concept.cpp
Normal file
@ -0,0 +1,142 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "testing_helpers.h"
|
||||
#include "std2_make_unique.hpp"
|
||||
#include "g2sink.h"
|
||||
#include "g2sinkwrapper.h"
|
||||
#include "g2sinkhandle.h"
|
||||
#include "g2logmessage.hpp"
|
||||
|
||||
|
||||
using namespace std;
|
||||
using namespace std2;
|
||||
using namespace testing_helpers;
|
||||
|
||||
class CoutSink {
|
||||
stringstream buffer;
|
||||
unique_ptr<ScopedOut> scope_ptr;
|
||||
|
||||
CoutSink() : scope_ptr(std2::make_unique<ScopedOut>(std::cout, &buffer)) { }
|
||||
public:
|
||||
void clear() { buffer.str(""); }
|
||||
std::string string() { return buffer.str(); }
|
||||
void save(g2::internal::LogEntry msg) { std::cout << msg; }
|
||||
|
||||
virtual ~CoutSink() final { }
|
||||
|
||||
static std::unique_ptr<CoutSink> createSink()
|
||||
{ return std::unique_ptr<CoutSink>(new CoutSink); }
|
||||
};
|
||||
|
||||
|
||||
namespace {
|
||||
typedef std::shared_ptr<g2::internal::SinkWrapper> SinkWrapperPtr;
|
||||
typedef g2::internal::LogEntry LogEntry;
|
||||
}
|
||||
|
||||
namespace g2 {
|
||||
|
||||
class Worker {
|
||||
std::vector<SinkWrapperPtr> _container; // should be hidden in a pimple with a bg active object
|
||||
std::unique_ptr<kjellkod::Active> _bg;
|
||||
|
||||
void bgSave(LogEntry msg) {
|
||||
for (auto& sink : _container) {
|
||||
sink->send(msg);
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
Worker() : _bg {
|
||||
kjellkod::Active::createActive()
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
~Worker() {
|
||||
_bg->send([this] { _container.clear(); });
|
||||
}
|
||||
|
||||
void save(LogEntry msg) {
|
||||
_bg->send([this, msg] { bgSave(msg); });
|
||||
} // will this be copied?
|
||||
//this is guaranteed to work std::bind(&Worker::bgSave, this, msg)); }
|
||||
|
||||
template<typename T, typename DefaultLogCall>
|
||||
std::unique_ptr< SinkHandle<T> > addSink(std::unique_ptr<T> unique, DefaultLogCall call) {
|
||||
auto shared = std::shared_ptr<T>(unique.release());
|
||||
auto sink = std::make_shared < internal::Sink<T> > (shared, call);
|
||||
auto add_sink_call = [this, sink] { _container.push_back(sink);
|
||||
|
||||
};
|
||||
auto wait_result = g2::spawn_task(add_sink_call, _bg.get());
|
||||
wait_result.wait();
|
||||
|
||||
auto handle = std2::make_unique< SinkHandle<T> >(sink);
|
||||
return handle;
|
||||
}
|
||||
};
|
||||
|
||||
} // g2
|
||||
|
||||
|
||||
|
||||
using namespace g2;
|
||||
using namespace g2::internal;
|
||||
|
||||
TEST(Sink, CreateHandle) {
|
||||
Worker worker;
|
||||
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
ASSERT_NE(nullptr, handle.get());
|
||||
}
|
||||
|
||||
TEST(Sink, OneSink__VerifyMsgIn) {
|
||||
Worker worker;
|
||||
auto handle = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
worker.save("Hello World!");
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto output = handle->call(&CoutSink::string);
|
||||
ASSERT_EQ("Hello World!", output.get());
|
||||
}
|
||||
|
||||
struct StringSink {
|
||||
std::string raw;
|
||||
void append(LogEntry entry) { raw.append(entry); }
|
||||
std::string string(){return raw; }
|
||||
};
|
||||
|
||||
|
||||
TEST(Sink, DualSink__VerifyMsgIn) {
|
||||
Worker worker;
|
||||
auto h1 = worker.addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
auto h2 = worker.addSink(std2::make_unique<StringSink>(), &StringSink::append);
|
||||
worker.save("Hello World!");
|
||||
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
auto first = h1->call(&CoutSink::string);
|
||||
auto second = h2->call(&StringSink::string);
|
||||
|
||||
|
||||
ASSERT_EQ("Hello World!", first.get());
|
||||
ASSERT_EQ("Hello World!", second.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Sink, DeletedSink__Exptect_badweak_ptr___exception) {
|
||||
auto worker = std2::make_unique<Worker>();
|
||||
auto h1 = worker->addSink(CoutSink::createSink(), &CoutSink::save);
|
||||
worker->save("Hello World!");
|
||||
worker.reset();
|
||||
|
||||
auto first = h1->call(&CoutSink::string);
|
||||
EXPECT_THROW(first.get(), std::bad_weak_ptr);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user