From 889c079fbc7a07b6f00c84cbe1d630884b69ce03 Mon Sep 17 00:00:00 2001 From: codereader Date: Thu, 10 Dec 2020 18:31:17 +0100 Subject: [PATCH] #5382: Add TestLogFile class, which will (unlike the regular DarkRadiant.log) append text to the output file, not clearing it on open. --- test/RadiantTest.h | 16 ++++++ test/TestLogFile.h | 79 ++++++++++++++++++++++++++ tools/msvc/Tests/Tests.vcxproj | 1 + tools/msvc/Tests/Tests.vcxproj.filters | 1 + 4 files changed, 97 insertions(+) create mode 100644 test/TestLogFile.h diff --git a/test/RadiantTest.h b/test/RadiantTest.h index 2422f7efea..ad24f77c32 100644 --- a/test/RadiantTest.h +++ b/test/RadiantTest.h @@ -10,6 +10,7 @@ #include "icommandsystem.h" #include "TestContext.h" +#include "TestLogFile.h" #include "HeadlessOpenGLContext.h" #include "module/CoreModule.h" #include "messages/GameConfigNeededMessage.h" @@ -37,6 +38,8 @@ class RadiantTest : std::shared_ptr _glContextModule; + std::unique_ptr _testLogFile; + protected: RadiantTest() { @@ -54,6 +57,8 @@ class RadiantTest : module::RegistryReference::Instance().setRegistry(radiant->getModuleRegistry()); module::initialiseStreams(radiant->getLogWriter()); + + initTestLog(); } catch (module::CoreModule::FailureException & ex) { @@ -107,11 +112,22 @@ class RadiantTest : ~RadiantTest() { + _coreModule->get()->getLogWriter().detach(_testLogFile.get()); + _testLogFile->close(); + _testLogFile.reset(); + module::shutdownStreams(); _coreModule.reset(); } protected: + void initTestLog() + { + auto fullPath = _context.getCacheDataPath() + "test.log"; + _testLogFile.reset(new TestLogFile(fullPath)); + _coreModule->get()->getLogWriter().attach(_testLogFile.get()); + } + virtual void setupGameFolder() {} diff --git a/test/TestLogFile.h b/test/TestLogFile.h new file mode 100644 index 0000000000..2e1c06077f --- /dev/null +++ b/test/TestLogFile.h @@ -0,0 +1,79 @@ +#pragma once + +#include +#include +#include +#include "ilogwriter.h" +#include "itextstream.h" + +namespace test +{ + +class TestLogFile : + public applog::ILogDevice +{ + // The log file name including path + std::string _logFilePath; + + // We write line by line + std::string _buffer; + + // The file stream which will be filled with bytes + std::ofstream _logStream; + + const char* const _timeFormat; + +public: + TestLogFile(const std::string& fullPath) : + _logFilePath(fullPath), + _logStream(_logFilePath.c_str(), std::ios_base::app), + _timeFormat("%Y-%m-%d %H:%M:%S") + {} + + // Returns true if the log stream was successfully opened + bool isOpen() + { + return _logStream.good(); + } + + void writeLog(const std::string& outputStr, applog::LogLevel level) override + { + _buffer.append(outputStr); + + // Hold back until we hit a newline + if (outputStr.rfind('\n') != std::string::npos) + { + std::time_t t = std::time(nullptr); + std::tm tm = *std::localtime(&t); + + // Write timestamp and thread information + _logStream << std::put_time(&tm, _timeFormat); + _logStream << " (" << std::this_thread::get_id() << ") "; + + // Insert the string into the stream and flush the buffer + _logStream << _buffer; + + _buffer.clear(); + _logStream.flush(); + } + } + + void close() + { + std::time_t t = std::time(nullptr); + std::tm tm = *std::localtime(&t); + rMessage() << std::put_time(&tm, _timeFormat) << " Closing log file." << std::endl; + + // Insert the last few remaining bytes into the stream + if (!_buffer.empty()) + { + _logStream << _buffer << std::endl; + _buffer.clear(); + } + + _logStream.flush(); + _logStream.close(); + } +}; + +} // namespace diff --git a/tools/msvc/Tests/Tests.vcxproj b/tools/msvc/Tests/Tests.vcxproj index c150421cc6..845f500326 100644 --- a/tools/msvc/Tests/Tests.vcxproj +++ b/tools/msvc/Tests/Tests.vcxproj @@ -65,6 +65,7 @@ + diff --git a/tools/msvc/Tests/Tests.vcxproj.filters b/tools/msvc/Tests/Tests.vcxproj.filters index 17deb91e74..86e7ddff3a 100644 --- a/tools/msvc/Tests/Tests.vcxproj.filters +++ b/tools/msvc/Tests/Tests.vcxproj.filters @@ -47,6 +47,7 @@ algorithm +