finalcut/test/flogger-test.cpp

410 lines
13 KiB
C++

/***********************************************************************
* flogger-test.cpp - FLogger unit tests *
* *
* This file is part of the FINAL CUT widget toolkit *
* *
* Copyright 2020 Markus Gans *
* *
* FINAL CUT is free software; you can redistribute it and/or modify *
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 3 of *
* the License, or (at your option) any later version. *
* *
* FINAL CUT is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program. If not, see *
* <http://www.gnu.org/licenses/>. *
***********************************************************************/
#include <memory>
#include <sstream>
#include <string>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TestFixture.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestRunner.h>
#include <final/final.h>
//----------------------------------------------------------------------
// class FLoggerTest
//----------------------------------------------------------------------
class myLogger : public finalcut::FLog
{
public:
void info (const std::string& entry) override
{
output << " Info: " << entry << std::endl;
}
void warn (const std::string& entry) override
{
output << " Warn: " << entry << std::endl;
}
void error (const std::string& entry) override
{
output << "Error: " << entry << std::endl;
}
void debug (const std::string& entry) override
{
output << "Debug: " << entry << std::endl;
}
void flush() override
{
// An implementation is not required in this context
}
void setOutputStream (const std::ostream& os) override
{ output.rdbuf(os.rdbuf()); }
void setLineEnding (LineEnding) override
{
// An implementation is not required in this context
}
void enableTimestamp() override
{
// An implementation is not required in this context
}
void disableTimestamp() override
{
// An implementation is not required in this context
}
private:
// Data member
std::ostream output{std::cerr.rdbuf()};
};
//----------------------------------------------------------------------
// class FLoggerTest
//----------------------------------------------------------------------
class FLoggerTest : public CPPUNIT_NS::TestFixture
{
public:
FLoggerTest()
{ }
protected:
void classNameTest();
void defaultObjectTest();
void lineEndingTest();
void timestampTest();
void fileTest();
void applicationObjectTest();
private:
// Adds code needed to register the test suite
CPPUNIT_TEST_SUITE (FLoggerTest);
// Add a methods to the test suite
CPPUNIT_TEST (classNameTest);
CPPUNIT_TEST (defaultObjectTest);
CPPUNIT_TEST (lineEndingTest);
CPPUNIT_TEST (timestampTest);
CPPUNIT_TEST (fileTest);
CPPUNIT_TEST (applicationObjectTest);
// End of test suite definition
CPPUNIT_TEST_SUITE_END();
};
//----------------------------------------------------------------------
void FLoggerTest::classNameTest()
{
finalcut::FLogger log;
const finalcut::FString& classname = log.getClassName();
CPPUNIT_ASSERT ( classname == "FLogger" );
}
//----------------------------------------------------------------------
void FLoggerTest::defaultObjectTest()
{
finalcut::FLogger log{};
std::ostringstream buf{};
log.setOutputStream(buf);
log << "Hello, World!" << std::flush; // Default level is "Info"
CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << "Hel" << "lo," << " Wor" << "ld!" << std::flush; // Several parts
CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << "Hello, World!" << std::endl; // std::endl
CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\n\r\n" );
buf.str(""); // Clear buffer
log << finalcut::FLog::LogLevel::Info << "Hello, World!" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << finalcut::FLog::LogLevel::Warn << "Hello, World!" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[WARNING] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << "Hello, World!" << std::flush; // Last level was "Warn"
CPPUNIT_ASSERT ( buf.str() == "[WARNING] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << finalcut::FLog::LogLevel::Error << "Hello, World!" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[ERROR] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << "Hello, World!" << std::flush; // Last level was "Error"
CPPUNIT_ASSERT ( buf.str() == "[ERROR] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << finalcut::FLog::LogLevel::Debug << "Hello, World!" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log << "Hello, World!" << std::flush; // Last level was "Debug"
CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Hello, World!\r\n" );
buf.str(""); // Clear buffer
// Without stream
log.info("Hello, World!");
CPPUNIT_ASSERT ( buf.str() == "[INFO] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log.warn("Hello, World!");
CPPUNIT_ASSERT ( buf.str() == "[WARNING] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log.error("Hello, World!");
CPPUNIT_ASSERT ( buf.str() == "[ERROR] Hello, World!\r\n" );
buf.str(""); // Clear buffer
log.debug("Hello, World!");
CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Hello, World!\r\n" );
buf.str(""); // Clear buffer
}
//----------------------------------------------------------------------
void FLoggerTest::lineEndingTest()
{
finalcut::FLogger log{};
std::ostringstream buf{};
log.setOutputStream(buf);
log.info("Line endings"); // Default = CRLF
CPPUNIT_ASSERT ( buf.str() == "[INFO] Line endings\r\n" );
buf.str(""); // Clear buffer
log.setLineEnding(finalcut::FLog::LineEnding::LF);
log.warn("Line endings");
CPPUNIT_ASSERT ( buf.str() == "[WARNING] Line endings\n" );
buf.str(""); // Clear buffer
log.setLineEnding(finalcut::FLog::LineEnding::CR);
log.error("Line endings");
CPPUNIT_ASSERT ( buf.str() == "[ERROR] Line endings\r" );
buf.str(""); // Clear buffer
log.setLineEnding(finalcut::FLog::LineEnding::CRLF);
log.debug("Line endings");
CPPUNIT_ASSERT ( buf.str() == "[DEBUG] Line endings\r\n" );
buf.str(""); // Clear buffer
}
//----------------------------------------------------------------------
void FLoggerTest::timestampTest()
{
finalcut::FLogger log{};
std::ostringstream buf{};
log.setOutputStream(buf);
log.info("Timestamp");
std::size_t length = buf.str().length();
CPPUNIT_ASSERT ( buf.str() == "[INFO] Timestamp\r\n" );
CPPUNIT_ASSERT ( length == 18 );
buf.str(""); // Clear buffer
log.enableTimestamp();
log.info("Timestamp");
length = buf.str().length();
CPPUNIT_ASSERT ( buf.str().substr(length - 18) == "[INFO] Timestamp\r\n" );
CPPUNIT_ASSERT ( length > 40 );
buf.str(""); // Clear buffer
log.disableTimestamp();
log.info("Timestamp");
length = buf.str().length();
CPPUNIT_ASSERT ( buf.str() == "[INFO] Timestamp\r\n" );
CPPUNIT_ASSERT ( length == 18 );
buf.str(""); // Clear buffer
}
//----------------------------------------------------------------------
void FLoggerTest::fileTest()
{
std::string filename = "test.log";
{
finalcut::FLogger log{};
std::ofstream file_stream(filename, std::ofstream::out);
log.setLineEnding (finalcut::FLog::LineEnding::LF);
log.setOutputStream(file_stream);
log.info("test1");
log.warn("test2");
log.error("test3");
log.debug("test4");
log << finalcut::FLog::LogLevel::Info << "streaming test1";
log << finalcut::FLog::LogLevel::Warn << "streaming test2";
log << finalcut::FLog::LogLevel::Error << "streaming test3";
log << finalcut::FLog::LogLevel::Debug << "streaming test4" << std::flush;
if ( file_stream.is_open() )
file_stream.close();
} // End of logging
std::string strings[] =
{
"[INFO] test1",
"[WARNING] test2",
"[ERROR] test3",
"[DEBUG] test4",
"[INFO] streaming test1",
"[WARNING] streaming test2",
"[ERROR] streaming test3",
"[DEBUG] streaming test4",
""
};
std::string line{};
std::ifstream file_stream{filename};
std::size_t i{0};
while ( ! file_stream.eof() && file_stream.good() )
{
getline(file_stream, line);
CPPUNIT_ASSERT ( line == strings[i] );
i++;
}
if ( file_stream.is_open() )
file_stream.close();
int ret = remove(filename.c_str()); // Delete file
if ( ret == -1 )
{
finalcut::FLogger log{};
log.setOutputStream(std::cerr);
log.setLineEnding (finalcut::FLog::LineEnding::LF);
log.error("Cannot delete the test.log file");
}
}
//----------------------------------------------------------------------
void FLoggerTest::applicationObjectTest()
{
// Save the rdbuf of clog
std::streambuf* default_clog_rdbuf = std::clog.rdbuf();
// Generation of a logger in a shared_ptr via a pointer
finalcut::FApplication::setLog (std::make_shared<finalcut::FLogger>());
// Get the shared_ptr with the base class
std::shared_ptr<finalcut::FLog> log = finalcut::FApplication::getLog();
std::ostringstream buf{};
log->setOutputStream(buf);
log->info("test1");
CPPUNIT_ASSERT ( buf.str() == "[INFO] test1\r\n" );
buf.str(""); // Clear buffer
log->warn("test2");
CPPUNIT_ASSERT ( buf.str() == "[WARNING] test2\r\n" );
buf.str(""); // Clear buffer
log->error("test3");
CPPUNIT_ASSERT ( buf.str() == "[ERROR] test3\r\n" );
buf.str(""); // Clear buffer
log->debug("test4");
CPPUNIT_ASSERT ( buf.str() == "[DEBUG] test4\r\n" );
buf.str(""); // Clear buffer
*log << "test5" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[INFO] test5\r\n" );
buf.str(""); // Clear buffer
*log << finalcut::FLog::LogLevel::Error << "test6" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[ERROR] test6\r\n" );
buf.str(""); // Clear buffer
// Logging to std::clog
std::clog << finalcut::FLog::LogLevel::Info << "test7" << std::flush;
CPPUNIT_ASSERT ( buf.str() == "[INFO] test7\r\n" );
buf.str(""); // Clear buffer
std::clog << finalcut::FLog::LogLevel::Warn << "test8" << std::endl;
CPPUNIT_ASSERT ( buf.str() == "[WARNING] test8\n\r\n" );
buf.str(""); // Clear buffer
// Replace the logger with another one
finalcut::FApplication::setLog(std::make_shared<myLogger>());
log = finalcut::FApplication::getLog();
log->setOutputStream(buf);
log->info("myLogger 1");
CPPUNIT_ASSERT ( buf.str() == " Info: myLogger 1\n" );
buf.str(""); // Clear buffer
log->warn("myLogger 2");
CPPUNIT_ASSERT ( buf.str() == " Warn: myLogger 2\n" );
buf.str(""); // Clear buffer
log->error("myLogger 3");
CPPUNIT_ASSERT ( buf.str() == "Error: myLogger 3\n" );
buf.str(""); // Clear buffer
log->debug("myLogger 4");
CPPUNIT_ASSERT ( buf.str() == "Debug: myLogger 4\n" );
buf.str(""); // Clear buffer
// Logging to std::clog with the replaced logger
std::clog << finalcut::FLog::LogLevel::Info << "myLogger 5" << std::flush;
CPPUNIT_ASSERT ( buf.str() == " Info: myLogger 5\n" );
buf.str(""); // Clear buffer
std::clog << finalcut::FLog::LogLevel::Error << "myLogger 6" << std::endl;
CPPUNIT_ASSERT ( buf.str() == "Error: myLogger 6\n\n" );
buf.str(""); // Clear buffer
// Reset to the default rdbuf of clog
std::clog.rdbuf(default_clog_rdbuf);
// Delete the global FApplication logger object
auto logger = &(finalcut::FApplication::getLog());
if ( logger )
delete logger;
}
// Put the test suite in the registry
CPPUNIT_TEST_SUITE_REGISTRATION (FLoggerTest);
// The general unit test main part
#include <main-test.inc>