Update QsLog to 2.1 snapshot 46b643d5bcbc

This commit is contained in:
Felix Kauselmann
2020-07-24 19:05:01 +02:00
parent c13ec618d0
commit 1568a5f253
45 changed files with 2579 additions and 269 deletions

View File

@ -0,0 +1,29 @@
set(PROJECTNAME QsLogUnitTest)
project(${PROJECTNAME})
find_package(Qt5Test REQUIRED)
include_directories(${QsLogUnitTest_SOURCE_DIR} ${QsLog_SOURCE_DIR})
if(QS_LOG_IS_SHARED_LIBRARY)
# Ugh, ugly hack
add_definitions(-UQSLOG_IS_SHARED_LIBRARY)
add_definitions(-DQSLOG_IS_SHARED_LIBRARY_IMPORT)
endif()
set(HEADER_FILES
TestLog.h
QtTestUtil/QtTestUtil.h
QtTestUtil/TestRegistration.h
QtTestUtil/TestRegistry.h
)
set(SOURCE_FILES
TestLog.cpp
QtTestUtil/SimpleChecker.cpp
QtTestUtil/TestRegistry.cpp
)
add_executable(${PROJECTNAME} ${SOURCE_FILES} ${HEADER_FILES})
target_link_libraries(${PROJECTNAME} QsLog Qt5::Core Qt5::Test)

View File

@ -0,0 +1,31 @@
/*
* Copyright (C) 2008 Remko Troncon
* Licensed under the MIT license.
* See COPYING for license details.
*/
#ifndef QtTestUtil_H
#define QtTestUtil_H
#include <QObject>
#include <QtTest/QtTest>
#include "QtTestUtil/TestRegistration.h"
/**
* A macro to register a test class.
*
* This macro will create a static variable which registers the
* testclass with the TestRegistry, and creates an instance of the
* test class.
*
* Execute this macro in the body of your unit test's .cpp file, e.g.
* class MyTest {
* ...
* };
*
* QTTESTUTIL_REGISTER_TEST(MyTest)
*/
#define QTTESTUTIL_REGISTER_TEST(TestClass) \
static QtTestUtil::TestRegistration<TestClass> TestClass##Registration
#endif

View File

@ -0,0 +1,17 @@
/*
* Copyright (C) 2008 Remko Troncon
* Licensed under the MIT license.
* See COPYING for license details.
*/
#include <QCoreApplication>
#include "QtTestUtil/TestRegistry.h"
/**
* Runs all tests registered with the QtTestUtil registry.
*/
int main(int argc, char* argv[]) {
QCoreApplication application(argc, argv);
return QtTestUtil::TestRegistry::getInstance()->runTests(argc, argv);
}

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2008 Remko Troncon
* Licensed under the MIT license.
* See COPYING for license details.
*/
#ifndef QtTestUtil_TestRegistration_H
#define QtTestUtil_TestRegistration_H
#include "QtTestUtil/TestRegistry.h"
namespace QtTestUtil {
/**
* A wrapper class around a test to manage registration and static
* creation of an instance of the test class.
* This class is used by QTTESTUTIL_REGISTER_TEST(), and you should not
* use this class directly.
*/
template<typename TestClass>
class TestRegistration {
public:
TestRegistration() {
test_ = new TestClass();
TestRegistry::getInstance()->registerTest(test_);
}
~TestRegistration() {
delete test_;
}
private:
TestClass* test_;
};
}
#endif

View File

@ -0,0 +1,30 @@
/*
* Copyright (C) 2008 Remko Troncon
* Licensed under the MIT license.
* See COPYING for license details.
*/
#include "QtTestUtil/TestRegistry.h"
#include <QtTest/QtTest>
namespace QtTestUtil {
TestRegistry* TestRegistry::getInstance() {
static TestRegistry registry;
return &registry;
}
void TestRegistry::registerTest(QObject* test) {
tests_ += test;
}
int TestRegistry::runTests(int argc, char* argv[]) {
int result = 0;
foreach(QObject* test, tests_) {
result |= QTest::qExec(test, argc, argv);
}
return result;
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2008 Remko Troncon
* Licensed under the MIT license.
* See COPYING for license details.
*/
#ifndef QtTestUtil_TestRegistry_H
#define QtTestUtil_TestRegistry_H
#include <QList>
class QObject;
namespace QtTestUtil {
/**
* A registry of QtTest test classes.
* All test classes registered with QTTESTUTIL_REGISTER_TEST add
* themselves to this registry. All registered tests can then be run at
* once using runTests().
*/
class TestRegistry {
public:
/**
* Retrieve the single instance of the registry.
*/
static TestRegistry* getInstance();
/**
* Register a QtTest test.
* This method is called by QTTESTUTIL_REGISTER_TEST, and you should
* not use this method directly.
*/
void registerTest(QObject*);
/**
* Run all registered tests using QTest::qExec()
*/
int runTests(int argc, char* argv[]);
private:
TestRegistry() {}
private:
QList<QObject*> tests_;
};
}
#endif

307
third_party/QsLog/unittest/TestLog.cpp vendored Normal file
View File

@ -0,0 +1,307 @@
#include "TestLog.h"
#include "QtTestUtil/QtTestUtil.h"
#include "QsLog.h"
#include "QsLogDest.h"
#include "QsLogDestFile.h"
#include "QsLogDestConsole.h"
#include "QsLogDestFile.h"
#include "QsLogDestFunctor.h"
#include <QTest>
#include <QSharedPointer>
#include <QtGlobal>
const QLatin1String destinationName1("mock1");
const QLatin1String destinationName2("mock2");
using MockDestinationPtrU = std::unique_ptr<MockDestination>;
// Needed to convert from removeDestination return value to the type that we initially added.
MockDestinationPtrU unique_cast(QsLogging::DestinationPtrU&& d)
{
MockDestinationPtrU md(dynamic_cast<MockDestination*>(d.release()));
Q_ASSERT(md.get());
return md;
}
void DummyLogFunction(const QsLogging::LogMessage&)
{
}
// Autotests for QsLog.
// These tests are based on using a mock destination to check what was logged. Destinations are
// owned by the log, that's why the add/remove ping-pong is needed in the tests.
class TestLog : public QObject
{
Q_OBJECT
public:
TestLog()
{
}
private slots:
void initTestCase();
void testAllLevels();
void testMessageText();
void testLevelChanges();
void testLevelParsing();
void testDestinationRemove();
void testWillRotate();
void testRotation_data();
void testRotation();
void testRotationNoBackup();
void testDestinationType();
private:
};
void TestLog::initTestCase()
{
using namespace QsLogging;
QCOMPARE(Logger::instance().loggingLevel(), InfoLevel);
Logger::instance().setLoggingLevel(TraceLevel);
QCOMPARE(Logger::instance().loggingLevel(), TraceLevel);
}
void TestLog::testAllLevels()
{
using namespace QsLogging;
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
Logger::instance().addDestination(std::move(mockDest));
QLOG_TRACE() << "trace level";
QLOG_DEBUG() << "debug level";
QLOG_INFO() << "info level";
QLOG_WARN() << "warn level";
QLOG_ERROR() << "error level";
QLOG_FATAL() << "fatal level";
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
QCOMPARE(mockDest->messageCount(), 6);
QCOMPARE(mockDest->messageCountForLevel(TraceLevel), 1);
QCOMPARE(mockDest->messageCountForLevel(DebugLevel), 1);
QCOMPARE(mockDest->messageCountForLevel(InfoLevel), 1);
QCOMPARE(mockDest->messageCountForLevel(WarnLevel), 1);
QCOMPARE(mockDest->messageCountForLevel(ErrorLevel), 1);
QCOMPARE(mockDest->messageCountForLevel(FatalLevel), 1);
}
void TestLog::testMessageText()
{
using namespace QsLogging;
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
Logger::instance().addDestination(std::move(mockDest));
QLOG_DEBUG() << "foobar";
QLOG_WARN() << "eiszeit";
QLOG_FATAL() << "ruh-roh!";
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
QVERIFY(mockDest->hasMessage("foobar", DebugLevel));
QVERIFY(mockDest->hasMessage("eiszeit", WarnLevel));
QVERIFY(mockDest->hasMessage("ruh-roh!", FatalLevel));
QCOMPARE(mockDest->messageCount(), 3);
}
void TestLog::testLevelChanges()
{
using namespace QsLogging;
MockDestinationPtrU mockDest1(new MockDestination(destinationName1));
MockDestinationPtrU mockDest2(new MockDestination(destinationName2));
Logger::instance().addDestination(std::move(mockDest1));
Logger::instance().addDestination(std::move(mockDest2));
using namespace QsLogging;
Logger::instance().setLoggingLevel(WarnLevel);
QCOMPARE(Logger::instance().loggingLevel(), WarnLevel);
QLOG_TRACE() << "one";
QLOG_DEBUG() << "two";
QLOG_INFO() << "three";
mockDest1 = unique_cast(Logger::instance().removeDestination(destinationName1));
mockDest2 = unique_cast(Logger::instance().removeDestination(destinationName2));
QCOMPARE(mockDest1->messageCount(), 0);
QCOMPARE(mockDest2->messageCount(), 0);
Logger::instance().addDestination(std::move(mockDest1));
Logger::instance().addDestination(std::move(mockDest2));
QLOG_WARN() << "warning";
QLOG_ERROR() << "error";
QLOG_FATAL() << "fatal";
mockDest1 = unique_cast(Logger::instance().removeDestination(destinationName1));
mockDest2 = unique_cast(Logger::instance().removeDestination(destinationName2));
QCOMPARE(mockDest1->messageCountForLevel(WarnLevel), 1);
QCOMPARE(mockDest1->messageCountForLevel(ErrorLevel), 1);
QCOMPARE(mockDest1->messageCountForLevel(FatalLevel), 1);
QCOMPARE(mockDest1->messageCount(), 3);
QCOMPARE(mockDest2->messageCountForLevel(WarnLevel), 1);
QCOMPARE(mockDest2->messageCountForLevel(ErrorLevel), 1);
QCOMPARE(mockDest2->messageCountForLevel(FatalLevel), 1);
QCOMPARE(mockDest2->messageCount(), 3);
}
void TestLog::testLevelParsing()
{
using namespace QsLogging;
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
Logger::instance().addDestination(std::move(mockDest));
QLOG_TRACE() << "one";
QLOG_DEBUG() << "two";
QLOG_INFO() << "three";
QLOG_WARN() << "warning";
QLOG_ERROR() << "error";
QLOG_FATAL() << "fatal";
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
using namespace QsLogging;
for(int i = 0;i < mockDest->messageCount();++i) {
bool conversionOk = false;
const MockDestination::Message& m = mockDest->messageAt(i);
QCOMPARE(Logger::levelFromLogMessage(m.text, &conversionOk), m.level);
QCOMPARE(Logger::levelFromLogMessage(m.text), m.level);
QCOMPARE(conversionOk, true);
}
}
void TestLog::testDestinationRemove()
{
using namespace QsLogging;
MockDestinationPtrU mockDest(new MockDestination(destinationName1));
MockDestinationPtrU toAddAndRemove(new MockDestination(destinationName2));
Logger::instance().addDestination(std::move(mockDest));
Logger::instance().addDestination(std::move(toAddAndRemove));
Logger::instance().setLoggingLevel(DebugLevel);
QLOG_INFO() << "one for all";
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
toAddAndRemove = unique_cast(Logger::instance().removeDestination(destinationName2));
QCOMPARE(mockDest->messageCount(), 1);
QCOMPARE(toAddAndRemove->messageCount(), 1);
Logger::instance().addDestination(std::move(mockDest));
QLOG_INFO() << "one for (almost) all";
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
QCOMPARE(mockDest->messageCount(), 2);
QCOMPARE(toAddAndRemove->messageCount(), 1);
QCOMPARE(toAddAndRemove->messageCountForLevel(InfoLevel), 1);
Logger::instance().addDestination(std::move(mockDest));
Logger::instance().addDestination(std::move(toAddAndRemove));
QLOG_INFO() << "another one for all";
mockDest = unique_cast(Logger::instance().removeDestination(destinationName1));
toAddAndRemove = unique_cast(Logger::instance().removeDestination(destinationName2));
QCOMPARE(mockDest->messageCount(), 3);
QCOMPARE(toAddAndRemove->messageCount(), 2);
QCOMPARE(toAddAndRemove->messageCountForLevel(InfoLevel), 2);
}
void TestLog::testWillRotate()
{
using namespace QsLogging;
MockSizeRotationStrategy rotationStrategy;
rotationStrategy.setBackupCount(1);
rotationStrategy.setMaximumSizeInBytes(10);
QCOMPARE(rotationStrategy.shouldRotate(), false);
rotationStrategy.includeMessageInCalculation(QLatin1String("12345"));
QCOMPARE(rotationStrategy.shouldRotate(), false);
rotationStrategy.includeMessageInCalculation(QLatin1String("12345"));
QCOMPARE(rotationStrategy.shouldRotate(), false);
rotationStrategy.includeMessageInCalculation(QLatin1String("1"));
QCOMPARE(rotationStrategy.shouldRotate(), true);
}
void TestLog::testRotation_data()
{
QTest::addColumn<int>("backupCount");
QTest::newRow("one backup") << 1;
QTest::newRow("three backups") << 3;
QTest::newRow("five backups") << 5;
QTest::newRow("ten backups") << 10;
}
void TestLog::testRotation()
{
using namespace QsLogging;
QFETCH(int, backupCount);
MockSizeRotationStrategy rotationStrategy;
rotationStrategy.setBackupCount(backupCount);
for (int i = 0;i < backupCount;++i) {
rotationStrategy.rotate();
QCOMPARE(rotationStrategy.filesList().size(), 1 + i + 1); // 1 log + "rotation count" backups
}
rotationStrategy.rotate();
QCOMPARE(rotationStrategy.filesList().size(), backupCount + 1); // 1 log + backup count
}
void TestLog::testRotationNoBackup()
{
using namespace QsLogging;
MockSizeRotationStrategy rotationStrategy;
rotationStrategy.setBackupCount(0);
rotationStrategy.setMaximumSizeInBytes(10);
rotationStrategy.rotate();
QCOMPARE(rotationStrategy.filesList().size(), 1); // log
}
void TestLog::testDestinationType()
{
using namespace QsLogging;
DestinationPtrU console = DestinationFactory::MakeDebugOutputDestination();
DestinationPtrU file = DestinationFactory::MakeFileDestination("test.log",
LogRotationOption::DisableLogRotation, MaxSizeBytes(5000), MaxOldLogCount(1));
DestinationPtrU func = DestinationFactory::MakeFunctorDestination(&DummyLogFunction);
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
Logger::instance().addDestination(std::move(console));
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), true);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
Logger::instance().addDestination(std::move(file));
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), true);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), true);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
Logger::instance().addDestination(std::move(func));
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), true);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), true);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), true);
Logger::instance().removeDestination(DebugOutputDestination::Type);
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), true);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), true);
Logger::instance().removeDestination(FileDestination::Type);
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), true);
Logger::instance().removeDestination(FunctorDestination::Type);
QCOMPARE(Logger::instance().hasDestinationOfType(DebugOutputDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FileDestination::Type), false);
QCOMPARE(Logger::instance().hasDestinationOfType(FunctorDestination::Type), false);
}
QTTESTUTIL_REGISTER_TEST(TestLog);
#include "TestLog.moc"

158
third_party/QsLog/unittest/TestLog.h vendored Normal file
View File

@ -0,0 +1,158 @@
#ifndef TESTLOG_H
#define TESTLOG_H
#include "QsLogDest.h"
#include "QsLogDestFile.h"
#include <QHash>
#include <QList>
#include <QString>
#include <QStringList>
#include <QDir>
// A destination that tracks log messages
class MockDestination : public QsLogging::Destination
{
public:
struct Message
{
Message() : level(QsLogging::TraceLevel) {}
QString text;
QsLogging::Level level;
};
public:
explicit MockDestination(const QLatin1String& myType = QLatin1String("mock"))
: mMyType(myType)
{
}
void write(const QsLogging::LogMessage& message) override
{
Message m;
m.text = message.formatted;
m.level = message.level;
mMessages.push_back(m);
++mCountByLevel[message.level];
}
bool isValid() override
{
return true;
}
QString type() const override
{
return mMyType;
}
void clear()
{
mMessages.clear();
mCountByLevel.clear();
}
int messageCount() const
{
return mMessages.count();
}
int messageCountForLevel(QsLogging::Level level) const
{
return mCountByLevel.value(level);
}
bool hasMessage(const QString &messageContent, QsLogging::Level level) const
{
Q_FOREACH (const Message &m, mMessages) {
if (m.level == level && m.text.contains(messageContent))
return true;
}
return false;
}
const Message& messageAt(int index)
{
Q_ASSERT(index >= 0 && index < messageCount());
return mMessages.at(index);
}
private:
QHash<QsLogging::Level,int> mCountByLevel;
QList<Message> mMessages;
QLatin1String mMyType;
};
// A rotation strategy that simulates file rotations.
// Stores a "file system" inside a string list and can perform some operations on it.
class MockSizeRotationStrategy : public QsLogging::SizeRotationStrategy
{
public:
MockSizeRotationStrategy()
: fakePath("FAKEPATH")
, logName("QsLog.txt")
{
setInitialInfo(QDir(fakePath).filePath(logName), 0);
files.append(logName);
}
const QStringList& filesList() {
return files;
}
void rotate() override {
SizeRotationStrategy::rotate();
files.append(logName);
}
protected:
bool removeFileAtPath(const QString& path) override {
QString editedPath = path;
if (editedPath.startsWith(fakePath)) {
editedPath.remove(0, fakePath.size() + 1);
const int indexOfPath = files.indexOf(editedPath);
if (indexOfPath != -1) {
files.removeAt(indexOfPath);
return true;
}
}
return false;
}
bool fileExistsAtPath(const QString& path) override {
QString editedPath = path;
if (editedPath.startsWith(fakePath)) {
editedPath.remove(0, fakePath.size() + 1);
return files.indexOf(editedPath) != -1;
}
return false;
}
bool renameFileFromTo(const QString& from, const QString& to) override {
QString editedFromPath = from;
QString editedToPath = to;
if (editedFromPath.startsWith(fakePath) && editedToPath.startsWith(fakePath)) {
editedFromPath.remove(0, fakePath.size() + 1);
editedToPath.remove(0, fakePath.size() + 1);
const int ind = files.indexOf(editedFromPath);
if (ind != -1) {
files.removeAll(editedFromPath);
files.append(editedToPath);
return true;
}
}
return false;
}
private:
QStringList files;
const QString fakePath;
const QString logName;
};
#endif // TESTLOG_H

29
third_party/QsLog/unittest/unittest.pro vendored Normal file
View File

@ -0,0 +1,29 @@
QT += core
TARGET = QsLogUnitTest
CONFIG += console qtestlib c++11
CONFIG -= app_bundle
TEMPLATE = app
# optionally enable address sanitizer
linux-g++|macx {
QMAKE_CXXFLAGS += -fsanitize=address
QMAKE_LFLAGS += -fsanitize=address
}
# test-case sources
SOURCES += TestLog.cpp
HEADERS += TestLog.h
# component sources
include(../QsLog.pri)
SOURCES += \
./QtTestUtil/TestRegistry.cpp \
./QtTestUtil/SimpleChecker.cpp
HEADERS += \
./QtTestUtil/TestRegistry.h \
./QtTestUtil/TestRegistration.h \
./QtTestUtil/QtTestUtil.h