summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDominik Holland <dominik.holland@pelagicore.com>2018-05-11 09:55:07 +0200
committerDominik Holland <dominik.holland@pelagicore.com>2018-06-19 14:55:52 +0000
commit72f4414062072f1516fbab6ce7107ed5527a7f8f (patch)
tree351941a6e862160c3d5982a86e051d2bc53397cb /tests
parented6fe178b59a6ddd335d5ede80d2ceda01b19cca (diff)
downloadqtivi-72f4414062072f1516fbab6ce7107ed5527a7f8f.tar.gz
Add the QIviPagingModel class
The QIviPagingModel is reusing the code from the QIviSearchAndBrowseModel and implements only the interface for retrieving the content of a model using "Paging". This commit just adds the new class. New functionality will be added in following commits, as well as using the new class as the base for QIviSearchAndBrowseModel. Task-number: AUTOSUITE-420 Change-Id: I45f068efcb1d76e566556ee6ff54f429dc6b28da Reviewed-by: Robert Griebl <robert.griebl@pelagicore.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/core/core.pro1
-rw-r--r--tests/auto/core/qivipagingmodel/qivipagingmodel.pro15
-rw-r--r--tests/auto/core/qivipagingmodel/testdata/listview.qml44
-rw-r--r--tests/auto/core/qivipagingmodel/tst_qivipagingmodel.cpp497
4 files changed, 557 insertions, 0 deletions
diff --git a/tests/auto/core/core.pro b/tests/auto/core/core.pro
index c20d7b1..435510f 100644
--- a/tests/auto/core/core.pro
+++ b/tests/auto/core/core.pro
@@ -6,6 +6,7 @@ SUBDIRS = servicemanagertest \
qiviabstractfeature \
qivipendingreply \
queryparser \
+ qivipagingmodel \
qivisearchandbrowsemodel \
QT_FOR_CONFIG += ivicore
diff --git a/tests/auto/core/qivipagingmodel/qivipagingmodel.pro b/tests/auto/core/qivipagingmodel/qivipagingmodel.pro
new file mode 100644
index 0000000..cbd880f
--- /dev/null
+++ b/tests/auto/core/qivipagingmodel/qivipagingmodel.pro
@@ -0,0 +1,15 @@
+QT += testlib ivicore quick
+
+TARGET = tst_qivipagingmodel
+QMAKE_PROJECT_NAME = $$TARGET
+CONFIG += testcase
+
+TEMPLATE = app
+
+SOURCES += \
+ tst_qivipagingmodel.cpp
+
+DEFINES += SRCDIR=\\\"$$PWD/\\\"
+
+DISTFILES += testdata/*
+
diff --git a/tests/auto/core/qivipagingmodel/testdata/listview.qml b/tests/auto/core/qivipagingmodel/testdata/listview.qml
new file mode 100644
index 0000000..0cd1242
--- /dev/null
+++ b/tests/auto/core/qivipagingmodel/testdata/listview.qml
@@ -0,0 +1,44 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtIvi module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.0
+import QtIvi 1.0
+
+ListView {
+ id: root
+
+ width: 200
+ height: 200
+
+ delegate: Text {
+ width: 200
+ height: 200
+
+ text: model.id ? model.id : ""
+ }
+}
diff --git a/tests/auto/core/qivipagingmodel/tst_qivipagingmodel.cpp b/tests/auto/core/qivipagingmodel/tst_qivipagingmodel.cpp
new file mode 100644
index 0000000..dc0c9a3
--- /dev/null
+++ b/tests/auto/core/qivipagingmodel/tst_qivipagingmodel.cpp
@@ -0,0 +1,497 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 Pelagicore AG
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtIvi module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT-QTAS$
+** Commercial License Usage
+** Licensees holding valid commercial Qt Automotive Suite licenses may use
+** this file in accordance with the commercial license agreement provided
+** with the Software or, alternatively, in accordance with the terms
+** contained in a written agreement between you and The Qt Company. For
+** licensing terms and conditions see https://www.qt.io/terms-conditions.
+** For further information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtTest>
+#include <QIviAbstractFeature>
+#include <QIviServiceManager>
+#include <QIviPagingModel>
+#include <QIviPagingModelInterface>
+#include <QIviSearchAndBrowseModelItem>
+#include <QQmlEngine>
+#include <QQmlContext>
+#include <QQmlComponent>
+#include <QScopedPointer>
+
+//TODO Add test with multiple model instances, requesting different data at the same time
+//TODO Test the signal without a valid identifier
+
+class TestBackend : public QIviPagingModelInterface
+{
+ Q_OBJECT
+
+public:
+
+ //Sets the capabilities this instance should report
+ void setCapabilities(QIviPagingModel::Capabilities capabilities)
+ {
+ m_caps = capabilities;
+ }
+
+ //Adds very simple Data which can be used for most of the unit tests
+ void initializeSimpleData()
+ {
+ m_list = createItemList("simple");
+ }
+
+ QList<QIviSearchAndBrowseModelItem> createItemList(const QString &name)
+ {
+ QList<QIviSearchAndBrowseModelItem> list;
+ for (int i=0; i<100; i++) {
+ QIviSearchAndBrowseModelItem item;
+ item.setId(name + QLatin1String(" ") + QString::number(i));
+ QVariantMap map;
+ map.insert("type", name);
+ map.insert("index", i);
+ item.setData(map);
+ list.append(item);
+ }
+ return list;
+ }
+
+ void initialize() override
+ {
+ emit initializationDone();
+ }
+
+ void fetchData(const QUuid &identifier, int start, int count) override
+ {
+ emit supportedCapabilitiesChanged(identifier, m_caps);
+
+ if (m_caps.testFlag(QIviPagingModel::SupportsGetSize))
+ emit countChanged(identifier, m_list.count());
+
+ QVariantList requestedItems;
+
+ int size = qMin(start + count, m_list.count());
+ for (int i = start; i < size; i++)
+ requestedItems.append(QVariant::fromValue(m_list.at(i)));
+
+ emit dataFetched(identifier, requestedItems, start, start + count < m_list.count());
+ }
+
+ void insert(int index, const QIviSearchAndBrowseModelItem item)
+ {
+ m_list.insert(index, item);
+ QVariantList variantList = { QVariant::fromValue(item) };
+
+ emit dataChanged(QUuid(), variantList, index, 0);
+ }
+
+ void remove(int index)
+ {
+ m_list.removeAt(index);
+
+ emit dataChanged(QUuid(), QVariantList(), index, 1);
+ }
+
+ void move(int currentIndex, int newIndex)
+ {
+ int min = qMin(currentIndex, newIndex);
+ int max = qMax(currentIndex, newIndex);
+
+ m_list.move(currentIndex, newIndex);
+ QVariantList variantLIst;
+ for (int i = min; i <= max; i++)
+ variantLIst.append(QVariant::fromValue(m_list.at(i)));
+
+ emit dataChanged(QUuid(), variantLIst, min, max - min + 1);
+ }
+
+private:
+ QList<QIviSearchAndBrowseModelItem> m_list;
+ QIviPagingModel::Capabilities m_caps;
+};
+
+class TestServiceObject : public QIviServiceObject
+{
+ Q_OBJECT
+
+public:
+ explicit TestServiceObject(QObject *parent = nullptr) :
+ QIviServiceObject(parent)
+ {
+ m_backend = new TestBackend;
+ m_interfaces << QIviPagingModel_iid;
+ }
+
+ QStringList interfaces() const { return m_interfaces; }
+ QIviFeatureInterface *interfaceInstance(const QString &interface) const
+ {
+ if (interface == QIviPagingModel_iid)
+ return testBackend();
+ else
+ return 0;
+ }
+
+ TestBackend *testBackend() const
+ {
+ return m_backend;
+ }
+
+private:
+ QStringList m_interfaces;
+ TestBackend *m_backend;
+};
+
+void verifyQml(QQmlEngine *engine, const QByteArray &qml)
+{
+ QQmlComponent component(engine);
+ component.setData(qml, QUrl());
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY2(obj, qPrintable(component.errorString()));
+}
+
+class tst_QIviPagingModel : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QIviPagingModel();
+
+private Q_SLOTS:
+ void cleanup();
+
+ void testClearServiceObject();
+
+ void testBasic_qml();
+ void testGetAt();
+ void testFetchMore_data();
+ void testFetchMore();
+ void testDataChangedMode();
+ void testReload();
+ void testDataChangedMode_jump();
+ void testEditing();
+ void testMissingCapabilities();
+
+private:
+ QIviServiceManager *manager;
+};
+
+tst_QIviPagingModel::tst_QIviPagingModel()
+ : manager(QIviServiceManager::instance())
+{
+}
+
+void tst_QIviPagingModel::cleanup()
+{
+ manager->unloadAllBackends();
+}
+
+void tst_QIviPagingModel::testClearServiceObject()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->initializeSimpleData();
+ service->testBackend()->setCapabilities(QIviPagingModel::SupportsGetSize);
+
+ QIviPagingModel defaultModel;
+ QIviPagingModel model;
+ model.setServiceObject(service);
+
+ //TODO enable when fixed
+ //model.setLoadingType(QIviSearchAndBrowseModel::DataChanged);
+ model.setChunkSize(20);
+ model.setFetchMoreThreshold(20);
+
+ QVERIFY(model.chunkSize() != defaultModel.chunkSize());
+ QVERIFY(model.fetchMoreThreshold() != defaultModel.fetchMoreThreshold());
+ QVERIFY(model.capabilities() != defaultModel.capabilities());
+ //QVERIFY(model.loadingType() != defaultModel.loadingType());
+ QVERIFY(model.rowCount() != defaultModel.rowCount());
+
+ QVERIFY(model.setServiceObject(nullptr));
+
+ QVERIFY(model.chunkSize() == defaultModel.chunkSize());
+ QVERIFY(model.fetchMoreThreshold() == defaultModel.fetchMoreThreshold());
+ QVERIFY(model.capabilities() == defaultModel.capabilities());
+ QVERIFY(model.loadingType() == defaultModel.loadingType());
+ QVERIFY(model.rowCount() == defaultModel.rowCount());
+}
+
+void tst_QIviPagingModel::testBasic_qml()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->initializeSimpleData();
+
+ QQmlEngine engine;
+ engine.rootContext()->setContextProperty("testBackend", service);
+ verifyQml(&engine, "import QtQuick 2.0; import QtIvi 1.0; PagingModel{}");
+ verifyQml(&engine, "import QtQuick 2.0; import QtIvi 1.0; PagingModel{ \
+ serviceObject: testBackend \n\
+ }");
+}
+
+void tst_QIviPagingModel::testGetAt()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ model.setServiceObject(service);
+
+ QIviSearchAndBrowseModelItem item = model.at<QIviSearchAndBrowseModelItem>(0);
+ QCOMPARE(item.id(), QLatin1String("simple 0"));
+
+ QVariant var = model.get(0);
+ QCOMPARE(var.value<QIviSearchAndBrowseModelItem>().id(), item.id());
+}
+
+void tst_QIviPagingModel::testFetchMore_data()
+{
+ QTest::addColumn<int>("chunkSize");
+ QTest::addColumn<int>("fetchMoreThreshold");
+ QTest::newRow("normal") << -1 << -1;
+ QTest::newRow("custom chunkSize") << 20 << -1;
+ QTest::newRow("custom fetchMoreThreshold") << -1 << 2;
+}
+
+void tst_QIviPagingModel::testFetchMore()
+{
+ QFETCH(int, chunkSize);
+ QFETCH(int, fetchMoreThreshold);
+
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ model.setServiceObject(service);
+
+ if (chunkSize != -1) {
+ QSignalSpy chunkSizeChangedSpy(&model, SIGNAL(chunkSizeChanged(int)));
+ model.setChunkSize(model.chunkSize());
+ QVERIFY(!chunkSizeChangedSpy.count());
+
+ model.setChunkSize(chunkSize);
+ QCOMPARE(model.chunkSize(), chunkSize);
+ QVERIFY(chunkSizeChangedSpy.count());
+ model.reload();
+ }
+
+ // Set the threshold
+ if (fetchMoreThreshold != -1) {
+ QSignalSpy fetchMoreThresholdChangedSpy(&model, SIGNAL(fetchMoreThresholdChanged(int)));
+ model.setFetchMoreThreshold(model.fetchMoreThreshold());
+ QVERIFY(!fetchMoreThresholdChangedSpy.count());
+
+ model.setFetchMoreThreshold(fetchMoreThreshold);
+ QCOMPARE(model.fetchMoreThreshold(), fetchMoreThreshold);
+ QVERIFY(fetchMoreThresholdChangedSpy.count());
+ }
+
+ QVERIFY(model.serviceObject());
+ QCOMPARE(model.loadingType(), QIviPagingModel::FetchMore);
+
+ QSignalSpy fetchMoreThresholdSpy(&model, SIGNAL(fetchMoreThresholdReached()));
+
+ // Ask for an item before the threshold, shouldn't trigger the threshold reached signal and fetch new data.
+ int offset = model.fetchMoreThreshold() + 1;
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(model.chunkSize() - offset).id(),
+ QLatin1String("simple ") + QString::number(model.chunkSize() - offset));
+ QVERIFY(!fetchMoreThresholdSpy.count());
+
+ QCOMPARE(model.rowCount(), model.chunkSize());
+ // By using model.at we already prefetch the next chunk of data
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(model.chunkSize() - 1).id(), QLatin1String("simple ") + QString::number(model.chunkSize() - 1));
+
+ QVERIFY(fetchMoreThresholdSpy.count());
+ fetchMoreThresholdSpy.clear();
+ QCOMPARE(model.rowCount(), model.chunkSize() * 2);
+
+// QListView view;
+// view.setModel(&model);
+// view.show();
+// QVERIFY(QTest::qWaitForWindowExposed(&view));
+ //view.scrollTo(model.index(model.chunkSize()));
+
+ //qDebug() << model.rowCount();
+}
+
+void tst_QIviPagingModel::testDataChangedMode()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->setCapabilities(QIviPagingModel::SupportsGetSize);
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ model.setServiceObject(service);
+ QVERIFY(model.serviceObject());
+
+ //TODO remove this section once we have fixed the capability race
+ QSignalSpy fetchMoreThresholdSpy(&model, SIGNAL(fetchMoreThresholdReached()));
+ QCOMPARE(model.rowCount(), model.chunkSize());
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(model.chunkSize() - 1).id(), QLatin1String("simple ") + QString::number(model.chunkSize() - 1));
+ QVERIFY(fetchMoreThresholdSpy.count());
+ fetchMoreThresholdSpy.clear();
+
+ QSignalSpy loadingTypeChangedSpy(&model, SIGNAL(loadingTypeChanged(QIviPagingModel::LoadingType)));
+ model.setLoadingType(model.loadingType());
+ QVERIFY(!loadingTypeChangedSpy.count());
+
+ model.setLoadingType(QIviPagingModel::DataChanged);
+ QCOMPARE(model.loadingType(), QIviPagingModel::DataChanged);
+ QVERIFY(loadingTypeChangedSpy.count());
+
+ QCOMPARE(model.rowCount(), 100);
+ // model.chunkSize() when workaround is removed
+ int testIndex = model.chunkSize() - 1;
+
+ // Asking for an item near inside the threshold range should trigger a new fetch.
+ QSignalSpy fetchDataSpy(service->testBackend(), SIGNAL(dataFetched(const QUuid &, const QList<QVariant> &, int , bool )));
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(testIndex).id(), QLatin1String("simple ") + QString::number(testIndex));
+ QVERIFY(fetchMoreThresholdSpy.count());
+ QVERIFY(fetchDataSpy.count());
+
+ // Test that we really fetched new data
+ QCOMPARE(fetchDataSpy.at(0).at(2).toInt(), testIndex + 1);
+}
+
+void tst_QIviPagingModel::testReload()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->setCapabilities(QIviPagingModel::SupportsGetSize);
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ QSignalSpy countChangedSpy(&model, SIGNAL(countChanged()));
+
+ model.setServiceObject(service);
+ QVERIFY(model.serviceObject());
+ countChangedSpy.wait(100);
+ QVERIFY(countChangedSpy.count());
+
+ QCOMPARE(model.rowCount(), model.chunkSize());
+ countChangedSpy.clear();
+
+ QSignalSpy resetSpy(&model, SIGNAL(modelReset()));
+ model.reload();
+ countChangedSpy.wait(100);
+ QCOMPARE(resetSpy.count(), 1);
+ QCOMPARE(countChangedSpy.count(), 2);
+ QCOMPARE(model.rowCount(), model.chunkSize());
+}
+
+void tst_QIviPagingModel::testDataChangedMode_jump()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->setCapabilities(QIviPagingModel::SupportsGetSize);
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ model.setServiceObject(service);
+ QVERIFY(model.serviceObject());
+
+ QSignalSpy loadingTypeChangedSpy(&model, SIGNAL(loadingTypeChanged(QIviPagingModel::LoadingType)));
+ model.setLoadingType(model.loadingType());
+ QVERIFY(!loadingTypeChangedSpy.count());
+
+ model.setLoadingType(QIviPagingModel::DataChanged);
+ QCOMPARE(model.loadingType(), QIviPagingModel::DataChanged);
+ QVERIFY(loadingTypeChangedSpy.count());
+
+ QCOMPARE(model.rowCount(), 100);
+
+ // Ask for the last item. This should just fetch the chunk which is needed.
+ QSignalSpy dataChangedSpy(&model, SIGNAL(dataChanged(const QModelIndex, const QModelIndex, const QVector<int>)));
+ QSignalSpy fetchDataSpy(service->testBackend(), SIGNAL(dataFetched(const QUuid &, const QList<QVariant> &, int , bool )));
+ model.get(99);
+ dataChangedSpy.wait();
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(99).id(), QLatin1String("simple ") + QString::number(99));
+ QVERIFY(fetchDataSpy.count());
+
+ // Test that we really fetched new data
+ int chunkBegin = int(99 / model.chunkSize()) * model.chunkSize();
+ QCOMPARE(fetchDataSpy.at(0).at(2).toInt(), chunkBegin);
+}
+
+void tst_QIviPagingModel::testEditing()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ model.setServiceObject(service);
+
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(0).id(), QLatin1String("simple 0"));
+
+ QIviSearchAndBrowseModelItem newItem;
+ newItem.setId(QLatin1String("testItem"));
+
+ // Add a new Item
+ QSignalSpy insertSpy(&model, SIGNAL(rowsInserted(const QModelIndex &, int , int )));
+ service->testBackend()->insert(0, newItem);
+ QVERIFY(insertSpy.count());
+ QCOMPARE(insertSpy.at(0).at(1).toInt(), 0);
+ QCOMPARE(insertSpy.at(0).at(2).toInt(), 0);
+
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(0).id(), newItem.id());
+
+ // Move the item to a new location
+ QSignalSpy moveSpy(&model, SIGNAL(dataChanged(const QModelIndex &, const QModelIndex &, const QVector<int> &)));
+ int newIndex = 10;
+ service->testBackend()->move(0, newIndex);
+ QVERIFY(moveSpy.count());
+ QCOMPARE(moveSpy.at(0).at(0).toModelIndex().row(), 0);
+ QCOMPARE(moveSpy.at(0).at(1).toModelIndex().row(), newIndex);
+
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(newIndex).id(), newItem.id());
+
+ // Remove the item again
+ QSignalSpy removedSpy(&model, SIGNAL(rowsRemoved(const QModelIndex &, int , int )));
+ service->testBackend()->remove(newIndex);
+ QVERIFY(removedSpy.count());
+ QCOMPARE(removedSpy.at(0).at(1).toInt(), newIndex);
+ QCOMPARE(removedSpy.at(0).at(2).toInt(), newIndex);
+
+ QCOMPARE(model.at<QIviSearchAndBrowseModelItem>(newIndex).id(), QLatin1String("simple 10"));
+}
+
+void tst_QIviPagingModel::testMissingCapabilities()
+{
+ TestServiceObject *service = new TestServiceObject();
+ manager->registerService(service, service->interfaces());
+ service->testBackend()->initializeSimpleData();
+
+ QIviPagingModel model;
+ model.setServiceObject(service);
+
+ QTest::ignoreMessage(QtWarningMsg, "The backend doesn't support the DataChanged loading type. This call will have no effect");
+ model.setLoadingType(QIviPagingModel::DataChanged);
+ QCOMPARE(model.loadingType(), QIviPagingModel::FetchMore);
+}
+
+QTEST_MAIN(tst_QIviPagingModel)
+
+#include "tst_qivipagingmodel.moc"
+