From 3fd956636c3cc61e305275a5f5c84f294845b149 Mon Sep 17 00:00:00 2001 From: Adam Higerd Date: Wed, 29 Jun 2022 18:41:51 -0500 Subject: [PATCH] unit tests and debugging --- src/platform/qt/CMakeLists.txt | 20 ++++++ src/platform/qt/library/LibraryModel.cpp | 71 ++----------------- src/platform/qt/library/LibraryModel.h | 16 ++--- src/platform/qt/test/library.cpp | 90 ++++++++++++++++++++++++ src/platform/qt/test/main.cpp | 19 +++++ src/platform/qt/test/spanset.cpp | 62 ++++++++++++++++ src/platform/qt/test/suite.h | 23 ++++++ src/platform/qt/utils.cpp | 42 +++++++++++ src/platform/qt/utils.h | 17 +++++ 9 files changed, 285 insertions(+), 75 deletions(-) create mode 100644 src/platform/qt/test/library.cpp create mode 100644 src/platform/qt/test/main.cpp create mode 100644 src/platform/qt/test/spanset.cpp create mode 100644 src/platform/qt/test/suite.h diff --git a/src/platform/qt/CMakeLists.txt b/src/platform/qt/CMakeLists.txt index a83d625d756..ab3e858dbf1 100644 --- a/src/platform/qt/CMakeLists.txt +++ b/src/platform/qt/CMakeLists.txt @@ -480,3 +480,23 @@ if(DISTBUILD AND NOT APPLE) add_custom_command(TARGET ${BINARY_NAME}-qt POST_BUILD COMMAND "${STRIP}" "$") endif() endif() + +if(BUILD_SUITE) + enable_testing() + find_package(${QT}Test) + if(${QT}Test_FOUND) + set(TEST_SRC + test/main.cpp + test/library.cpp + test/spanset.cpp + utils.cpp + library/LibraryModel.cpp + ) + add_executable(test-platform-qt WIN32 ${TEST_SRC}) + target_link_libraries(test-platform-qt ${PLATFORM_LIBRARY} ${BINARY_NAME} ${QT_LIBRARIES} ${QT}::Test) + set_target_properties(test-platform-qt PROPERTIES COMPILE_DEFINITIONS "${FEATURE_DEFINES};${FUNCTION_DEFINES};${OS_DEFINES};${QT_DEFINES}" COMPILE_OPTIONS "${FEATURE_FLAGS}") + add_test(platform-qt test-platform-qt) + else() + message("${QT}Test not found") + endif() +endif() diff --git a/src/platform/qt/library/LibraryModel.cpp b/src/platform/qt/library/LibraryModel.cpp index 2e08417d128..6804852ec54 100644 --- a/src/platform/qt/library/LibraryModel.cpp +++ b/src/platform/qt/library/LibraryModel.cpp @@ -5,7 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "LibraryModel.h" -#include "utils.h" +#include "../utils.h" #include #include @@ -16,69 +16,8 @@ using namespace QGBA; -namespace QGBA { - -struct SpanSet { - struct Span { - int left; - int right; - - bool operator<(const Span& other) const { return left < other.left; } - bool operator>(const Span& other) const { return left > other.left; } - }; - - void add(int pos) { - bool found = false; - for (Span& span : spans) { - if (pos == span.left - 1) { - span.left = pos; - found = true; - } else if (pos == span.right + 1) { - span.right = pos; - found = true; - } - } - if (!found) { - spans << Span{ pos, pos }; - return; - } - } - - void merge() { - int numSpans = spans.size(); - if (!numSpans) { - return; - } - sort(); - QVector merged({ spans[0] }); - int lastRight = merged[0].right; - for (int i = 1; i < numSpans; i++) { - int right = spans[i].right; - if (spans[i].left - 1 <= lastRight) { - merged.back().right = right; - } else { - merged << spans[i]; - } - lastRight = right; - } - } - - void sort(bool reverse = false) { - if (reverse) { - std::sort(spans.begin(), spans.end(), std::greater()); - } else { - std::sort(spans.begin(), spans.end()); - } - } - - QVector spans; -}; - -} - -LibraryModel::LibraryModel(LibraryController* parent) +LibraryModel::LibraryModel(QObject* parent) : QAbstractItemModel(parent) - , m_controller(parent) , m_treeMode(false) , m_showFilename(false) { @@ -288,7 +227,7 @@ QModelIndex LibraryModel::index(int row, int column, const QModelIndex& parent) if (!parent.isValid()) { return createIndex(row, column, quintptr(-1)); } - if (!m_treeMode || parent.internalId() != quintptr(-1)) { + if (!m_treeMode || parent.internalId() != quintptr(-1) || parent.column() != 0) { return QModelIndex(); } return createIndex(row, column, parent.row()); @@ -302,7 +241,7 @@ QModelIndex LibraryModel::parent(const QModelIndex& child) const { } int LibraryModel::columnCount(const QModelIndex& parent) const { - if (!parent.isValid() || !parent.parent().isValid()) { + if (!parent.isValid() || (parent.column() == 0 && !parent.parent().isValid())) { return MAX_COLUMN + 1; } return 0; @@ -311,7 +250,7 @@ int LibraryModel::columnCount(const QModelIndex& parent) const { int LibraryModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) { if (m_treeMode) { - if (parent.row() < 0 || parent.row() >= m_pathOrder.size()) { + if (parent.row() < 0 || parent.row() >= m_pathOrder.size() || parent.column() != 0) { return 0; } return m_pathIndex[m_pathOrder[parent.row()]].size(); diff --git a/src/platform/qt/library/LibraryModel.h b/src/platform/qt/library/LibraryModel.h index 5040d701f56..21ee8264ad3 100644 --- a/src/platform/qt/library/LibraryModel.h +++ b/src/platform/qt/library/LibraryModel.h @@ -16,7 +16,7 @@ class QTreeView; namespace QGBA { -class LibraryModel final : public QAbstractItemModel, public AbstractGameList { +class LibraryModel final : public QAbstractItemModel { Q_OBJECT public: @@ -33,18 +33,18 @@ Q_OBJECT FullPathRole = Qt::UserRole + 1, }; - explicit LibraryModel(LibraryController* parent = nullptr); + explicit LibraryModel(QObject* parent = nullptr); bool treeMode() const; void setTreeMode(bool tree); bool showFilename() const; - void setShowFilename(bool show) override; + void setShowFilename(bool show); - void resetEntries(const QList& items) override; - void addEntries(const QList& items) override; - void updateEntries(const QList& items) override; - void removeEntries(const QList& items) override; + void resetEntries(const QList& items); + void addEntries(const QList& items); + void updateEntries(const QList& items); + void removeEntries(const QList& items); QModelIndex index(const QString& game) const; QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; @@ -65,8 +65,6 @@ Q_OBJECT void addEntriesTree(const QList& items); void addEntryInternal(const LibraryEntry& item); - LibraryController* m_controller; - bool m_treeMode; bool m_showFilename; diff --git a/src/platform/qt/test/library.cpp b/src/platform/qt/test/library.cpp new file mode 100644 index 00000000000..bca0ead6c3f --- /dev/null +++ b/src/platform/qt/test/library.cpp @@ -0,0 +1,90 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "suite.h" +#include "platform/qt/library/LibraryModel.h" + +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) +#include +#endif + +#include +#include + +using namespace QGBA; + +class LibraryModelTest : public QObject { +Q_OBJECT + +private: + LibraryModel* model = nullptr; + + LibraryEntry makeGBA(const QString& base, const QString& name, uint32_t crc) { + LibraryEntry entry; + entry.base = base; + entry.filename = name + ".gba"; + entry.fullpath = base + "/" + entry.filename; + entry.title = name; + entry.internalTitle = name.toUpper().toUtf8(); + entry.internalCode = entry.internalTitle.replace(" ", "").left(4); + entry.platform = mPLATFORM_GBA; + entry.filesize = entry.fullpath.size() * 4; + entry.crc32 = crc; + return entry; + } + + LibraryEntry makeGB(const QString& base, const QString& name, uint32_t crc) { + LibraryEntry entry = makeGBA(base, name, crc); + entry.filename = name + ".gb"; + entry.fullpath = base + "/" + entry.filename; + entry.platform = mPLATFORM_GB; + entry.filesize /= 4;; + return entry; + } + + void addTestGames1() { + model->addEntries({ + makeGBA("/gba", "Test Game", 0x12345678), + makeGBA("/gba", "Another", 0x23456789), + makeGB("/gb", "Old Game", 0x87654321), + }); + } + +private slots: + void init() { + model = new LibraryModel(); +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + new QAbstractItemModelTester(model, QAbstractItemModelTester::FailureReportingMode::QtTest, model); +#endif + } + + void cleanup() { + delete model; + model = nullptr; + } + + void initList() { + addTestGames1(); + QCOMPARE(model->rowCount(), 3); + } + + void initTree() { + QSignalSpy resetSpy(model, SIGNAL(modelReset())); + model->setTreeMode(true); + QVERIFY(resetSpy.count()); + addTestGames1(); + int gbRow = 0, gbaRow = 1; + if (model->index(0, 0).data() == "gba") { + gbaRow = 0; + gbRow = 1; + } + QCOMPARE(model->rowCount(), 2); + QCOMPARE(model->rowCount(model->index(gbRow, 0)), 1); + QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 2); + } +}; + +M_REGISTER_QT_TEST(LibraryModelTest) +#include "library.moc" diff --git a/src/platform/qt/test/main.cpp b/src/platform/qt/test/main.cpp new file mode 100644 index 00000000000..28a42241599 --- /dev/null +++ b/src/platform/qt/test/main.cpp @@ -0,0 +1,19 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "suite.h" + +QList registeredTests; + +int main(int argc, char** argv) { + int err = 0; + for (TestRegistrar* test : registeredTests) { + int result = test->main(argc, argv); + if (result && !err) { + err = result; + } + } + return err; +} diff --git a/src/platform/qt/test/spanset.cpp b/src/platform/qt/test/spanset.cpp new file mode 100644 index 00000000000..0391a72fd7a --- /dev/null +++ b/src/platform/qt/test/spanset.cpp @@ -0,0 +1,62 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "suite.h" +#include "platform/qt/utils.h" + +#include + +using namespace QGBA; + +class SpanSetTest : public QObject { +Q_OBJECT + +private: + void debugSpans(const SpanSet& spanSet) { + QStringList debug; + for (auto span : spanSet.spans) { + debug << QStringLiteral("[%1, %2]").arg(span.left).arg(span.right); + } + qDebug() << QStringLiteral("SpanSet{%1}").arg(debug.join(", ")); + } + +private slots: + void oneSpan() { + SpanSet spanSet; + spanSet.add(1); + spanSet.add(2); + spanSet.add(3); + QCOMPARE(spanSet.spans.size(), 1); + spanSet.merge(); + QCOMPARE(spanSet.spans.size(), 1); + } + + void twoSpans() { + SpanSet spanSet; + spanSet.add(1); + spanSet.add(2); + spanSet.add(4); + QCOMPARE(spanSet.spans.size(), 2); + spanSet.merge(); + QCOMPARE(spanSet.spans.size(), 2); + } + + void mergeSpans() { + SpanSet spanSet; + spanSet.add(1); + spanSet.add(3); + spanSet.add(2); + spanSet.add(5); + spanSet.add(4); + spanSet.add(7); + spanSet.add(8); + QCOMPARE(spanSet.spans.size(), 4); + spanSet.merge(); + QCOMPARE(spanSet.spans.size(), 2); + } +}; + +M_REGISTER_QT_TEST(SpanSetTest) +#include "spanset.moc" diff --git a/src/platform/qt/test/suite.h b/src/platform/qt/test/suite.h new file mode 100644 index 00000000000..6aae5f7e051 --- /dev/null +++ b/src/platform/qt/test/suite.h @@ -0,0 +1,23 @@ +/* Copyright (c) 2013-2022 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#pragma once + +#define QT_NO_OPENGL + +#include +#include + +struct TestRegistrar { + virtual int main(int argc, char** argv) = 0; +}; + +extern QList registeredTests; + +#define M_REGISTER_QT_TEST(Class) \ + static struct Class ## Registrar : TestRegistrar { \ + QTEST_MAIN(Class) \ + Class ## Registrar() { registeredTests << this; } \ + } registrar_ ## Class; diff --git a/src/platform/qt/utils.cpp b/src/platform/qt/utils.cpp index 8b273cb6d6d..afd3a795af0 100644 --- a/src/platform/qt/utils.cpp +++ b/src/platform/qt/utils.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "utils.h" +#include #include namespace QGBA { @@ -59,4 +60,45 @@ bool convertAddress(const QHostAddress* input, Address* output) { return true; } +void SpanSet::add(int pos) { + for (Span& span : spans) { + if (pos == span.left - 1) { + span.left = pos; + return; + } else if (pos == span.right + 1) { + span.right = pos; + return; + } + } + spans << Span{ pos, pos }; +} + +void SpanSet::merge() { + int numSpans = spans.size(); + if (!numSpans) { + return; + } + sort(); + QVector merged({ spans[0] }); + int lastRight = merged[0].right; + for (int i = 1; i < numSpans; i++) { + int right = spans[i].right; + if (spans[i].left - 1 <= lastRight) { + merged.back().right = right; + } else { + merged << spans[i]; + } + lastRight = right; + } + spans = merged; +} + +void SpanSet::sort(bool reverse) { + if (reverse) { + std::sort(spans.begin(), spans.end(), std::greater()); + } else { + std::sort(spans.begin(), spans.end()); + } +} + } diff --git a/src/platform/qt/utils.h b/src/platform/qt/utils.h index ca9ef027fff..fc99542ce46 100644 --- a/src/platform/qt/utils.h +++ b/src/platform/qt/utils.h @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -67,4 +68,20 @@ constexpr const T& clamp(const T& v, const T& lo, const T& hi) { } #endif +struct SpanSet { + struct Span { + int left; + int right; + + inline bool operator<(const Span& other) const { return left < other.left; } + inline bool operator>(const Span& other) const { return left > other.left; } + }; + + void add(int pos); + void merge(); + void sort(bool reverse = false); + + QVector spans; +}; + }