Add per-module unit-test dirs for the Release 2 scope
One unit-test/ directory per module/target, mirroring the existing TetraIF/unit-test/ layout (one QtTest executable per module, guarded by BUILD_TESTING and the module target, each registered with ctest): Lts/Common/CodeGen codegen_unit_test Lts/Common/LtsCoordinate ltscoordinate_unit_test Lts/Common/LtsSession ltssession_unit_test Lts/DDS/Core ddscore_unit_test Lts/DDS/QosProfile ddsqos_unit_test Lts/Tools/LogViewer logviewer_unit_test Lts/Tools/SqlBrowser sqlbrowser_unit_test Z/src/NGLLogger ngllogger_unit_test Z/src/WMS_Interface wms_json_ds_unit_test Z/src/nglapplication nglcoreapplication_unit_test Z/src/nglcompression nglcompression_unit_test Z/src/nglsettings nglsettings_unit_test Z/src/ngltranslator ngltranslator_unit_test Where a module is built with hidden visibility and has no export macro (LogViewer, SqlBrowser, ngltranslator, NGLLogger, nglcompression, nglsettings), its sources are compiled directly into the test executable, the same pattern as prtcnv_unit_test. ctest baseline in the container (QT_QPA_PLATFORM=offscreen): 20/23 passed (13 new + 7 pre-existing in-scope tests), 3 Not Run as before (nglcomp_test, GrantleeParserSmoke, utils_test). README: ctest baseline table extended to the 23 registered tests and section 2.4 now documents the per-module test layout. ddsview has no unit test (GUI tool, XmlHelper needs the DDS dynamic-xtypes runtime).
This commit is contained in:
1 parent
a62b729577
commit
09b6df8bc3
40 files changed
+4966
-17
No files matched your search
@@ -64,3 +64,8 @@ if(QT6_GUI_AVAILABLE)
|
||||
endif()
|
||||
|
||||
NGL_INSTALL_TARGET(LogViewer)
|
||||
|
||||
#
|
||||
# Unit tests
|
||||
#
|
||||
ADD_SUBDIRECTORY(unit-test)
|
||||
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# Unit tests for the LogViewer module.
|
||||
# One test executable per module, each registered with ctest.
|
||||
#
|
||||
if (NOT BUILD_TESTING)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# --- LogViewer: log table model + sort/filter proxy.
|
||||
# --- The module is an executable, so the model sources are compiled directly
|
||||
# --- into the test (same pattern as the LogView test in TetraIF/unit-test).
|
||||
if (TARGET LogViewer)
|
||||
ADD_EXECUTABLE(logviewer_unit_test
|
||||
logviewer_unit_test.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../logviewtablemodel.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../sortfiltermodel.cpp)
|
||||
TARGET_LINK_LIBRARIES(logviewer_unit_test
|
||||
NGLLogger
|
||||
Qt6::Core
|
||||
Qt6::Gui
|
||||
Qt6::Test
|
||||
)
|
||||
ADD_TEST(NAME logviewer_unit_test COMMAND $<TARGET_FILE:logviewer_unit_test>)
|
||||
endif()
|
||||
@@ -0,0 +1,553 @@
|
||||
//
|
||||
// Unit tests for the LogViewer module: LogViewTableModel (log line storage,
|
||||
// column/role data access, standard level colors) and SortFilterModel
|
||||
// (string/date filtering and date-aware sorting).
|
||||
//
|
||||
// Both classes are the module's non-GUI logic (QAbstractTableModel /
|
||||
// QSortFilterProxyModel, no widgets needed); they are compiled from the
|
||||
// LogViewer executable sources. The other LogViewer classes are filter
|
||||
// widgets and the main window.
|
||||
//
|
||||
#include "../logviewtablemodel.h"
|
||||
#include "../sortfiltermodel.h"
|
||||
|
||||
#include <NGLLogger/NGLLoggerBootstrap.h>
|
||||
|
||||
#include <QtCore/QDateTime>
|
||||
#include <QtTest/QTest>
|
||||
|
||||
using LogInformation = LogViewTableModel::logInformation;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
LogInformation makeLine(const QDateTime &date, const QString &level, const QString &logger,
|
||||
const QString &data, const QString &location)
|
||||
{
|
||||
LogInformation line;
|
||||
line.date = date;
|
||||
line.level = level;
|
||||
line.logger = logger;
|
||||
line.data = data;
|
||||
line.location = location;
|
||||
return line;
|
||||
}
|
||||
|
||||
QDateTime d(const QString &iso)
|
||||
{
|
||||
return QDateTime::fromString(iso, Qt::ISODate);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class logviewer_unit_test : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
|
||||
// LogViewTableModel
|
||||
void tableModelEmptyDimensions();
|
||||
void tableModelSetDataAndReadRoles();
|
||||
void tableModelInvalidIndex();
|
||||
void tableModelHeaderData();
|
||||
void tableModelStandardLevelColors();
|
||||
void tableModelAdjustColorsAndReset();
|
||||
void tableModelAddDataAndLength();
|
||||
void tableModelSetDataByIndex();
|
||||
void tableModelStartEndDateTimeSignals();
|
||||
|
||||
// SortFilterModel
|
||||
void proxyStringFilter();
|
||||
void proxyDateStringFilterEdgeCases();
|
||||
void proxyDateFilter();
|
||||
void proxyResetAllFilter();
|
||||
void proxySortByDate();
|
||||
void proxySortByLevel();
|
||||
void proxyFigureFilterOutSignal();
|
||||
};
|
||||
|
||||
void logviewer_unit_test::initTestCase()
|
||||
{
|
||||
// LogViewTableModel's constructor resolves its logger from the NGL root
|
||||
// logger, so it must exist before the model is instantiated.
|
||||
NGL::NGLLoggerBootstrap::createNGLRootLogger("log4cxx.props", false);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// LogViewTableModel
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void logviewer_unit_test::tableModelEmptyDimensions()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
// note: the overrides in LogViewTableModel redeclare the parameter without
|
||||
// the base class' default value
|
||||
QCOMPARE(model.rowCount(QModelIndex()), 0);
|
||||
QCOMPARE(model.columnCount(QModelIndex()), LogViewTableModel::colLast + 1);
|
||||
QCOMPARE(model.length(), 0);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelSetDataAndReadRoles()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
const QDateTime date = d(QStringLiteral("2024-05-06T12:34:56"));
|
||||
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(date, QStringLiteral("INFO"), QStringLiteral("main"), QStringLiteral("hello"),
|
||||
QStringLiteral("a.cpp:42"))
|
||||
<< makeLine(d(QStringLiteral("2024-05-07T08:00:00")), QStringLiteral("WARN"),
|
||||
QStringLiteral("net"), QStringLiteral("world"), QStringLiteral("b.cpp:7"));
|
||||
model.setData(lines);
|
||||
|
||||
QCOMPARE(model.rowCount(QModelIndex()), 2);
|
||||
QCOMPARE(model.length(), 2);
|
||||
|
||||
// DisplayRole per column
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colDate), Qt::DisplayRole).toString().
|
||||
startsWith(QStringLiteral("2024-05-06 12:34:56,")), true);
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("INFO"));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colLogger), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("main"));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colData), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("hello"));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colLocation), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("a.cpp:42"));
|
||||
|
||||
// UserRole carries the raw QDateTime of the date column
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colDate), Qt::UserRole).toDateTime(), date);
|
||||
|
||||
// itemAt: note the date format uses dashes between the time parts
|
||||
QCOMPARE(model.itemAt(1, LogViewTableModel::colDate).startsWith(QStringLiteral("2024-05-07 08-00-00,")),
|
||||
true);
|
||||
QCOMPARE(model.itemAt(0, LogViewTableModel::colLevel), QStringLiteral("INFO"));
|
||||
QCOMPARE(model.itemAt(0, LogViewTableModel::colData), QStringLiteral("hello"));
|
||||
// unknown column index -> empty string
|
||||
QCOMPARE(model.itemAt(0, 99), QString());
|
||||
|
||||
// replacing all data
|
||||
model.setData(QVector<LogInformation>());
|
||||
QCOMPARE(model.rowCount(QModelIndex()), 0);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelInvalidIndex()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("x.cpp:1"));
|
||||
model.setData(lines);
|
||||
|
||||
// invalid index -> invalid QVariant for any role
|
||||
const QModelIndex invalid = QModelIndex();
|
||||
QVERIFY(!model.data(invalid, Qt::DisplayRole).isValid());
|
||||
QVERIFY(!model.data(invalid, Qt::UserRole).isValid());
|
||||
QVERIFY(!model.data(invalid, Qt::BackgroundRole).isValid());
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelHeaderData()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
QCOMPARE(model.headerData(LogViewTableModel::colDate, Qt::Horizontal, Qt::DisplayRole).toString(),
|
||||
QStringLiteral("Date"));
|
||||
QCOMPARE(model.headerData(LogViewTableModel::colLevel, Qt::Horizontal, Qt::DisplayRole).toString(),
|
||||
QStringLiteral("Level"));
|
||||
QCOMPARE(model.headerData(LogViewTableModel::colLogger, Qt::Horizontal, Qt::DisplayRole).toString(),
|
||||
QStringLiteral("Logger"));
|
||||
QCOMPARE(model.headerData(LogViewTableModel::colData, Qt::Horizontal, Qt::DisplayRole).toString(),
|
||||
QStringLiteral("Data"));
|
||||
QCOMPARE(model.headerData(LogViewTableModel::colLocation, Qt::Horizontal, Qt::DisplayRole).toString(),
|
||||
QStringLiteral("Location"));
|
||||
|
||||
// vertical orientation and out-of-range section fall through to
|
||||
// QAbstractTableModel::headerData (1-based: section+1 horizontal, 1 vertical)
|
||||
QCOMPARE(model.headerData(0, Qt::Vertical, Qt::DisplayRole).toString(), QStringLiteral("1"));
|
||||
QCOMPARE(model.headerData(99, Qt::Horizontal, Qt::DisplayRole).toString(), QStringLiteral("100"));
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelStandardLevelColors()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("WARN"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("ERROR"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("FATAL"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("DEBUG"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("TRACE"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("CUSTOM"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
model.setData(lines);
|
||||
|
||||
const int col = LogViewTableModel::colLevel;
|
||||
QCOMPARE(model.data(model.index(0, col), Qt::BackgroundRole).value<QColor>(), Qt::blue);
|
||||
QCOMPARE(model.data(model.index(0, col), Qt::ForegroundRole).value<QColor>(), Qt::white);
|
||||
QCOMPARE(model.data(model.index(1, col), Qt::BackgroundRole).value<QColor>(), Qt::yellow);
|
||||
QCOMPARE(model.data(model.index(1, col), Qt::ForegroundRole).value<QColor>(), Qt::black);
|
||||
QCOMPARE(model.data(model.index(2, col), Qt::BackgroundRole).value<QColor>(), Qt::darkRed);
|
||||
QCOMPARE(model.data(model.index(2, col), Qt::ForegroundRole).value<QColor>(), Qt::white);
|
||||
QCOMPARE(model.data(model.index(3, col), Qt::BackgroundRole).value<QColor>(), Qt::red);
|
||||
QCOMPARE(model.data(model.index(3, col), Qt::ForegroundRole).value<QColor>(), Qt::black);
|
||||
QCOMPARE(model.data(model.index(4, col), Qt::BackgroundRole).value<QColor>(), Qt::green);
|
||||
QCOMPARE(model.data(model.index(4, col), Qt::ForegroundRole).value<QColor>(), Qt::black);
|
||||
QCOMPARE(model.data(model.index(5, col), Qt::BackgroundRole).value<QColor>(), Qt::lightGray);
|
||||
QCOMPARE(model.data(model.index(5, col), Qt::ForegroundRole).value<QColor>(), Qt::black);
|
||||
|
||||
// unknown level: no color registered -> invalid variants
|
||||
QVERIFY(!model.data(model.index(6, col), Qt::BackgroundRole).isValid());
|
||||
QVERIFY(!model.data(model.index(6, col), Qt::ForegroundRole).isValid());
|
||||
|
||||
// other columns have no background/foreground color
|
||||
QVERIFY(!model.data(model.index(0, LogViewTableModel::colData), Qt::BackgroundRole).isValid());
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelAdjustColorsAndReset()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("WARN"), QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
model.setData(lines);
|
||||
const int col = LogViewTableModel::colLevel;
|
||||
|
||||
// adjustCellColor only affects levels that are already registered
|
||||
model.adjustCellColor(Qt::red, QStringLiteral("INFO"));
|
||||
QCOMPARE(model.data(model.index(0, col), Qt::BackgroundRole).value<QColor>(), Qt::red);
|
||||
// unknown level: no effect
|
||||
model.adjustCellColor(Qt::green, QStringLiteral("NOPE"));
|
||||
QCOMPARE(model.data(model.index(1, col), Qt::BackgroundRole).value<QColor>(), Qt::yellow);
|
||||
|
||||
// adjustFontColor
|
||||
model.adjustFontColor(Qt::black, QStringLiteral("INFO"));
|
||||
QCOMPARE(model.data(model.index(0, col), Qt::ForegroundRole).value<QColor>(), Qt::black);
|
||||
|
||||
// reset() clears the data and restores the standard colors
|
||||
QVERIFY(model.reset());
|
||||
QCOMPARE(model.length(), 0);
|
||||
QCOMPARE(model.rowCount(QModelIndex()), 0);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelAddDataAndLength()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
QCOMPARE(model.length(), 0);
|
||||
model.addData(makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("l.cpp:1")));
|
||||
QCOMPARE(model.length(), 1);
|
||||
model.addData(makeLine(d(QStringLiteral("2024-01-02T00:00:00")), QStringLiteral("WARN"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("l.cpp:1")));
|
||||
QCOMPARE(model.length(), 2);
|
||||
QCOMPARE(model.data(model.index(1, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("WARN"));
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelSetDataByIndex()
|
||||
{
|
||||
LogViewTableModel model;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
model.setData(lines);
|
||||
|
||||
// only Qt::EditRole is accepted
|
||||
QVERIFY(!model.setData(model.index(0, LogViewTableModel::colLevel), QStringLiteral("X"),
|
||||
Qt::DisplayRole));
|
||||
|
||||
QVERIFY(model.setData(model.index(0, LogViewTableModel::colLevel), QStringLiteral("ERROR"),
|
||||
Qt::EditRole));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("ERROR"));
|
||||
|
||||
QVERIFY(model.setData(model.index(0, LogViewTableModel::colLogger), QStringLiteral("other"),
|
||||
Qt::EditRole));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colLogger), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("other"));
|
||||
|
||||
QVERIFY(model.setData(model.index(0, LogViewTableModel::colData), QStringLiteral("new data"),
|
||||
Qt::EditRole));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colData), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("new data"));
|
||||
|
||||
QVERIFY(model.setData(model.index(0, LogViewTableModel::colLocation), QStringLiteral("m.cpp:9"),
|
||||
Qt::EditRole));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colLocation), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("m.cpp:9"));
|
||||
|
||||
const QDateTime newDate = d(QStringLiteral("2024-02-02T02:02:02"));
|
||||
QVERIFY(model.setData(model.index(0, LogViewTableModel::colDate), newDate, Qt::EditRole));
|
||||
QCOMPARE(model.data(model.index(0, LogViewTableModel::colDate), Qt::UserRole).toDateTime(), newDate);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::tableModelStartEndDateTimeSignals()
|
||||
{
|
||||
// empty model: no signals
|
||||
LogViewTableModel empty;
|
||||
bool started = false;
|
||||
bool ended = false;
|
||||
QObject::connect(&empty, &LogViewTableModel::startTimeSetted, [&started](const QDateTime &) { started = true; });
|
||||
QObject::connect(&empty, &LogViewTableModel::endTimeSetted, [&ended](const QDateTime &) { ended = true; });
|
||||
empty.startDateTime();
|
||||
empty.endDateTime();
|
||||
QVERIFY(!started);
|
||||
QVERIFY(!ended);
|
||||
|
||||
// populated model: first/last line date
|
||||
LogViewTableModel model;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-03-01T00:00:00")), QStringLiteral("INFO"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-03-02T00:00:00")), QStringLiteral("WARN"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-03-03T00:00:00")), QStringLiteral("ERROR"), QStringLiteral("l"),
|
||||
QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
model.setData(lines);
|
||||
|
||||
QDateTime start;
|
||||
QDateTime end;
|
||||
QObject::connect(&model, &LogViewTableModel::startTimeSetted, [&start](const QDateTime &t) { start = t; });
|
||||
QObject::connect(&model, &LogViewTableModel::endTimeSetted, [&end](const QDateTime &t) { end = t; });
|
||||
model.startDateTime();
|
||||
model.endDateTime();
|
||||
QCOMPARE(start, d(QStringLiteral("2024-03-01T00:00:00")));
|
||||
QCOMPARE(end, d(QStringLiteral("2024-03-03T00:00:00")));
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SortFilterModel
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
void logviewer_unit_test::proxyStringFilter()
|
||||
{
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("main"), QStringLiteral("alpha"), QStringLiteral("a.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-02T00:00:00")), QStringLiteral("WARN"),
|
||||
QStringLiteral("net"), QStringLiteral("beta"), QStringLiteral("b.cpp:2"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-03T00:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("net"), QStringLiteral("gamma"), QStringLiteral("c.cpp:3"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
QCOMPARE(proxy.rowCount(), 3);
|
||||
QVERIFY(proxy.stringFilterIsEmpty());
|
||||
|
||||
// setStringFilter itself does not re-run the proxy filter (only the date
|
||||
// setters and resetAllFilter do); mainwindow.cpp calls
|
||||
// m_filterProxyModel->invalidate() after every setStringFilter, so the
|
||||
// tests do the same.
|
||||
// filter on the level column (col 1)
|
||||
proxy.setStringFilter(LogViewTableModel::colLevel, QStringLiteral("WARN"));
|
||||
proxy.invalidate();
|
||||
QCOMPARE(proxy.rowCount(), 1);
|
||||
QCOMPARE(proxy.data(proxy.index(0, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("WARN"));
|
||||
|
||||
// combined with the logger column (col 2)
|
||||
proxy.setStringFilter(LogViewTableModel::colLogger, QStringLiteral("net"));
|
||||
proxy.invalidate();
|
||||
QCOMPARE(proxy.rowCount(), 1);
|
||||
QCOMPARE(proxy.data(proxy.index(0, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("WARN"));
|
||||
|
||||
// replacing an existing filter: "net" does not match the new text "main"
|
||||
proxy.setStringFilter(LogViewTableModel::colLogger, QStringLiteral("main"));
|
||||
proxy.invalidate();
|
||||
// WARN rows have logger "net" -> nothing left
|
||||
QCOMPARE(proxy.rowCount(), 0);
|
||||
|
||||
// case sensitivity: a fresh column filter is stored as-is and the row data
|
||||
// "beta" does not match "BETA" (contains() is case sensitive)
|
||||
proxy.resetAllFilter();
|
||||
QCOMPARE(proxy.rowCount(), 3);
|
||||
proxy.setStringFilter(LogViewTableModel::colData, QStringLiteral("BETA"));
|
||||
proxy.invalidate();
|
||||
QCOMPARE(proxy.rowCount(), 0);
|
||||
|
||||
// setStringFilter keeps the old filter when the new text matches the old
|
||||
// one case-insensitively, so the stored filter is still "BETA"
|
||||
proxy.setStringFilter(LogViewTableModel::colData, QStringLiteral("beta"));
|
||||
proxy.invalidate();
|
||||
QCOMPARE(proxy.rowCount(), 0);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::proxyDateStringFilterEdgeCases()
|
||||
{
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T00:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
|
||||
// column range is validated: out-of-range columns are ignored
|
||||
proxy.setStringFilter(-1, QStringLiteral("x"));
|
||||
proxy.setStringFilter(5, QStringLiteral("x"));
|
||||
proxy.setStringFilter(99, QStringLiteral("x"));
|
||||
QVERIFY(proxy.stringFilterIsEmpty());
|
||||
QCOMPARE(proxy.rowCount(), 1);
|
||||
|
||||
// an empty filter string still counts as "contained" for the activation
|
||||
// report (columns 3 and 4 only check presence, columns 1 and 2 check for
|
||||
// non-emptiness)
|
||||
proxy.setStringFilter(LogViewTableModel::colData, QString());
|
||||
QVERIFY(!proxy.stringFilterIsEmpty());
|
||||
QVector<bool> activated = proxy.activatedStringFilter();
|
||||
QCOMPARE(activated.size(), 5);
|
||||
QVERIFY(!activated.at(0));
|
||||
QVERIFY(!activated.at(1));
|
||||
QVERIFY(!activated.at(2));
|
||||
QVERIFY(activated.at(3));
|
||||
QVERIFY(!activated.at(4));
|
||||
|
||||
// empty filter does not filter any row (contains("") is always true)
|
||||
QCOMPARE(proxy.rowCount(), 1);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::proxyDateFilter()
|
||||
{
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T10:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-02T10:00:00")), QStringLiteral("WARN"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-03T10:00:00")), QStringLiteral("ERROR"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
|
||||
// only start date: filter not active (both ends required)
|
||||
proxy.setStartDateFilter(d(QStringLiteral("2024-01-01T10:00:00")));
|
||||
QCOMPARE(proxy.rowCount(), 3);
|
||||
QVector<bool> activated = proxy.activatedStringFilter();
|
||||
QVERIFY(!activated.at(0));
|
||||
|
||||
// start and end: window is exclusive on both ends
|
||||
proxy.setEndDateFilter(d(QStringLiteral("2024-01-03T10:00:00")));
|
||||
QCOMPARE(proxy.rowCount(), 1);
|
||||
QCOMPARE(proxy.data(proxy.index(0, LogViewTableModel::colDate), Qt::UserRole).toDateTime(),
|
||||
d(QStringLiteral("2024-01-02T10:00:00")));
|
||||
activated = proxy.activatedStringFilter();
|
||||
QVERIFY(activated.at(0));
|
||||
|
||||
// setting the same start date again is a no-op (and must not break the filter)
|
||||
proxy.setStartDateFilter(d(QStringLiteral("2024-01-01T10:00:00")));
|
||||
QCOMPARE(proxy.rowCount(), 1);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::proxyResetAllFilter()
|
||||
{
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T10:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("main"), QStringLiteral("alpha"), QStringLiteral("a.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-02T10:00:00")), QStringLiteral("WARN"),
|
||||
QStringLiteral("net"), QStringLiteral("beta"), QStringLiteral("b.cpp:2"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
|
||||
proxy.setStringFilter(LogViewTableModel::colLevel, QStringLiteral("WARN"));
|
||||
proxy.setStringFilter(LogViewTableModel::colLogger, QStringLiteral("net"));
|
||||
proxy.setStartDateFilter(d(QStringLiteral("2024-01-01T10:00:00")));
|
||||
proxy.setEndDateFilter(d(QStringLiteral("2024-01-02T10:00:00")));
|
||||
QCOMPARE(proxy.rowCount(), 0);
|
||||
|
||||
proxy.resetAllFilter();
|
||||
QVERIFY(proxy.stringFilterIsEmpty());
|
||||
QCOMPARE(proxy.rowCount(), 2);
|
||||
QVector<bool> activated = proxy.activatedStringFilter();
|
||||
for (const bool active : activated)
|
||||
QVERIFY(!active);
|
||||
}
|
||||
|
||||
void logviewer_unit_test::proxySortByDate()
|
||||
{
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-03T10:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-01T10:00:00")), QStringLiteral("WARN"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-02T10:00:00")), QStringLiteral("ERROR"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
proxy.sort(LogViewTableModel::colDate, Qt::AscendingOrder);
|
||||
|
||||
QCOMPARE(proxy.rowCount(), 3);
|
||||
QCOMPARE(proxy.data(proxy.index(0, LogViewTableModel::colDate), Qt::UserRole).toDateTime(),
|
||||
d(QStringLiteral("2024-01-01T10:00:00")));
|
||||
QCOMPARE(proxy.data(proxy.index(1, LogViewTableModel::colDate), Qt::UserRole).toDateTime(),
|
||||
d(QStringLiteral("2024-01-02T10:00:00")));
|
||||
QCOMPARE(proxy.data(proxy.index(2, LogViewTableModel::colDate), Qt::UserRole).toDateTime(),
|
||||
d(QStringLiteral("2024-01-03T10:00:00")));
|
||||
}
|
||||
|
||||
void logviewer_unit_test::proxySortByLevel()
|
||||
{
|
||||
// non-date columns fall back to the default QVariant comparison
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T10:00:00")), QStringLiteral("WARN"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-02T10:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"))
|
||||
<< makeLine(d(QStringLiteral("2024-01-03T10:00:00")), QStringLiteral("DEBUG"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
proxy.sort(LogViewTableModel::colLevel, Qt::AscendingOrder);
|
||||
|
||||
QCOMPARE(proxy.data(proxy.index(0, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("DEBUG"));
|
||||
QCOMPARE(proxy.data(proxy.index(1, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("INFO"));
|
||||
QCOMPARE(proxy.data(proxy.index(2, LogViewTableModel::colLevel), Qt::DisplayRole).toString(),
|
||||
QStringLiteral("WARN"));
|
||||
}
|
||||
|
||||
void logviewer_unit_test::proxyFigureFilterOutSignal()
|
||||
{
|
||||
LogViewTableModel source;
|
||||
QVector<LogInformation> lines;
|
||||
lines << makeLine(d(QStringLiteral("2024-01-01T10:00:00")), QStringLiteral("INFO"),
|
||||
QStringLiteral("l"), QStringLiteral("d"), QStringLiteral("l.cpp:1"));
|
||||
source.setData(lines);
|
||||
|
||||
SortFilterModel proxy;
|
||||
proxy.setSourceModel(&source);
|
||||
|
||||
QVector<bool> lastFilter;
|
||||
int calls = 0;
|
||||
QObject::connect(&proxy, &SortFilterModel::theseFilterAreActivated,
|
||||
[&lastFilter, &calls](const QVector<bool> &filter) {
|
||||
lastFilter = filter;
|
||||
++calls;
|
||||
});
|
||||
|
||||
proxy.figureFilterOut();
|
||||
QCOMPARE(calls, 1);
|
||||
QCOMPARE(lastFilter, QVector<bool>({false, false, false, false, false}));
|
||||
|
||||
proxy.setStringFilter(LogViewTableModel::colLevel, QStringLiteral("INFO"));
|
||||
proxy.figureFilterOut();
|
||||
QCOMPARE(calls, 2);
|
||||
QCOMPARE(lastFilter, QVector<bool>({false, true, false, false, false}));
|
||||
}
|
||||
|
||||
QTEST_MAIN(logviewer_unit_test)
|
||||
#include "logviewer_unit_test.moc"
|
||||
Reference in new issue
Block a user