/* * Copyright (C) 2011, 2013 Canonical, Ltd. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ // local #include "qlimitproxymodelqml.h" #include "ModelTest.h" // Qt #include #include #include #include #include class MockListModel : public QAbstractListModel { Q_OBJECT public: MockListModel(QObject* parent = 0) : QAbstractListModel(parent) { } int rowCount(const QModelIndex& /* parent */ = QModelIndex()) const override { return m_list.size(); } QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override { if (!index.isValid() || index.row() < 0 || index.row() >= m_list.size() || role != Qt::DisplayRole) { return QVariant(); } return QVariant(m_list[index.row()]); } QHash roleNames() const override { return m_roles; } void setRoles(const QHash &roles) { m_roles = roles; } void clear() { beginRemoveRows(QModelIndex(), 0, m_list.count() - 1); m_list.clear(); endRemoveRows(); } bool insertRows(int row, int count, const QModelIndex &parent=QModelIndex()) override { beginInsertRows(parent, row, row+count-1); for (int i=0; i m_roles; }; class MirrorModel : public QObject { Q_OBJECT public: MirrorModel(QAbstractItemModel *model) : m_mirror(model) { connect(model, &QAbstractItemModel::rowsInserted, this, &MirrorModel::rowsInserted); connect(model, &QAbstractItemModel::rowsRemoved, this, &MirrorModel::rowsRemoved); connect(model, &QAbstractItemModel::dataChanged, this, &MirrorModel::dataChanged); } void check() { QCOMPARE(m_list.count(), m_mirror->rowCount()); for (int i = 0; i < m_list.count(); ++i) { QCOMPARE(m_list[i], m_mirror->data(m_mirror->index(i, 0)).toString()); } } private Q_SLOTS: void rowsInserted(const QModelIndex &parent, int start, int end) { QVERIFY(!parent.isValid()); for (int i = start; i <= end; ++i) { m_list.insert(i, m_mirror->data(m_mirror->index(i, 0)).toString()); } } void rowsRemoved(const QModelIndex &parent, int start, int end) { QVERIFY(!parent.isValid()); for (int i = end; i >= start; --i) { m_list.removeAt(i); } } void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight) { QVERIFY(topLeft.isValid()); QVERIFY(bottomRight.isValid()); QVERIFY(!topLeft.parent().isValid()); QVERIFY(!bottomRight.parent().isValid()); for (int i = topLeft.row(); i <= bottomRight.row(); ++i) { m_list[i] = m_mirror->data(m_mirror->index(i, 0)).toString(); } } private: QStringList m_list; QAbstractItemModel *m_mirror; }; class QLimitProxyModelTest : public QObject { Q_OBJECT private Q_SLOTS: void initTestCase() { qRegisterMetaType("QModelIndex"); } void testRoleNamesSetAfter() { QLimitProxyModelQML proxy; MockListModel model; QHash roles; proxy.setModel(&model); roles[0] = "role0"; roles[1] = "role1"; model.setRoles(roles); QCOMPARE(model.roleNames(), proxy.roleNames()); } void testRoleNamesSetBefore() { QLimitProxyModelQML proxy; MockListModel model; QHash roles; roles[0] = "role0"; roles[1] = "role1"; model.setRoles(roles); proxy.setModel(&model); QCOMPARE(model.roleNames(), proxy.roleNames()); } void testCountSetAfter() { QLimitProxyModelQML proxy; MockListModel model; model.insertRows(0, 5); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); proxy.setModel(&model); QCOMPARE(proxy.rowCount(), 5); QVERIFY(spyOnCountChanged.count() >= 1); } void testCountInsert() { QLimitProxyModelQML proxy; MockListModel model; proxy.setModel(&model); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); model.insertRows(0, 5); QCOMPARE(proxy.rowCount(), 5); QCOMPARE(spyOnCountChanged.count(), 1); } void testCountRemove() { QLimitProxyModelQML proxy; MockListModel model; model.insertRows(0, 5); proxy.setModel(&model); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); model.removeRows(0, 3); QCOMPARE(proxy.rowCount(), 2); QCOMPARE(spyOnCountChanged.count(), 1); } void testLimitCount() { QLimitProxyModelQML proxy; MockListModel model; proxy.setModel(&model); proxy.setLimit(3); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); model.insertRows(0, 5); QCOMPARE(proxy.rowCount(), 3); QCOMPARE(spyOnCountChanged.count(), 1); } void testLimitLesserThanCount() { QLimitProxyModelQML proxy; MockListModel model; QList arguments; model.insertRows(0, 10); proxy.setModel(&model); QSignalSpy spyOnRowsRemoved(&proxy, &QLimitProxyModelQML::rowsRemoved); QSignalSpy spyOnRowsInserted(&proxy, &QLimitProxyModelQML::rowsInserted); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); proxy.setLimit(5); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 1); QCOMPARE(spyOnRowsRemoved.count(), 1); arguments = spyOnRowsRemoved.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 5); QCOMPARE(arguments.at(2).toInt(), 9); QCOMPARE(proxy.rowCount(), 5); spyOnRowsRemoved.clear(); spyOnCountChanged.clear(); proxy.setLimit(7); QCOMPARE(spyOnRowsInserted.count(), 1); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsInserted.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 5); QCOMPARE(arguments.at(2).toInt(), 6); QCOMPARE(proxy.rowCount(), 7); spyOnRowsInserted.clear(); spyOnCountChanged.clear(); proxy.setLimit(3); QCOMPARE(spyOnRowsRemoved.count(), 1); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsRemoved.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 3); QCOMPARE(arguments.at(2).toInt(), 6); QCOMPARE(proxy.rowCount(), 3); spyOnRowsRemoved.clear(); spyOnCountChanged.clear(); } void testLimitGreaterThanCount() { QLimitProxyModelQML proxy; MockListModel model; QList arguments; model.insertRows(0, 5); proxy.setModel(&model); QSignalSpy spyOnRowsRemoved(&proxy, &QLimitProxyModelQML::rowsRemoved); QSignalSpy spyOnRowsInserted(&proxy, &QLimitProxyModelQML::rowsInserted); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); proxy.setLimit(7); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); QCOMPARE(proxy.rowCount(), 5); proxy.setLimit(5); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); QCOMPARE(proxy.rowCount(), 5); proxy.setLimit(3); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnRowsRemoved.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsRemoved.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 3); QCOMPARE(arguments.at(2).toInt(), 4); QCOMPARE(proxy.rowCount(), 3); spyOnRowsRemoved.clear(); spyOnCountChanged.clear(); proxy.setLimit(4); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsInserted.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 3); QCOMPARE(arguments.at(2).toInt(), 3); QCOMPARE(proxy.rowCount(), 4); spyOnRowsInserted.clear(); spyOnCountChanged.clear(); proxy.setLimit(7); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsInserted.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 4); QCOMPARE(arguments.at(2).toInt(), 4); QCOMPARE(proxy.rowCount(), 5); spyOnRowsInserted.clear(); spyOnCountChanged.clear(); } void testLimitMinusOne() { QLimitProxyModelQML proxy; MockListModel model; QList arguments; model.insertRows(0, 5); proxy.setModel(&model); QSignalSpy spyOnRowsRemoved(&proxy, &QLimitProxyModelQML::rowsRemoved); QSignalSpy spyOnRowsInserted(&proxy, &QLimitProxyModelQML::rowsInserted); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); proxy.setLimit(7); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); QCOMPARE(proxy.rowCount(), 5); proxy.setLimit(-1); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); QCOMPARE(proxy.rowCount(), 5); proxy.setLimit(3); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnRowsRemoved.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsRemoved.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 3); QCOMPARE(arguments.at(2).toInt(), 4); QCOMPARE(proxy.rowCount(), 3); spyOnRowsRemoved.clear(); spyOnCountChanged.clear(); proxy.setLimit(-1); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsInserted.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 3); QCOMPARE(arguments.at(2).toInt(), 4); QCOMPARE(proxy.rowCount(), 5); spyOnRowsInserted.clear(); spyOnCountChanged.clear(); } void testLimitInsert() { QLimitProxyModelQML proxy; MockListModel model; QList arguments; proxy.setModel(&model); proxy.setLimit(7); QSignalSpy spyOnRowsRemoved(&proxy, &QLimitProxyModelQML::rowsRemoved); QSignalSpy spyOnRowsInserted(&proxy, &QLimitProxyModelQML::rowsInserted); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); model.insertRows(0, 5); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsInserted.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 0); QCOMPARE(arguments.at(2).toInt(), 4); QCOMPARE(proxy.rowCount(), 5); spyOnRowsInserted.clear(); spyOnCountChanged.clear(); model.insertRows(2, 2); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 1); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsInserted.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 2); QCOMPARE(arguments.at(2).toInt(), 3); QCOMPARE(proxy.rowCount(), 7); spyOnRowsInserted.clear(); spyOnCountChanged.clear(); model.insertRows(7, 3); QCOMPARE(proxy.rowCount(), 7); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); } void testLimitRemove() { QLimitProxyModelQML proxy; MockListModel model; QList arguments; proxy.setModel(&model); proxy.setLimit(7); model.insertRows(0, 12); QCOMPARE(proxy.rowCount(), 7); QSignalSpy spyOnRowsRemoved(&proxy, &QLimitProxyModelQML::rowsRemoved); QSignalSpy spyOnRowsInserted(&proxy, &QLimitProxyModelQML::rowsInserted); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); model.removeRows(7, 3); QCOMPARE(proxy.rowCount(), 7); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); model.removeRows(2, 2); QCOMPARE(spyOnRowsRemoved.count(), 0); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 0); QCOMPARE(proxy.rowCount(), 7); model.removeRows(0, 7); QCOMPARE(spyOnRowsRemoved.count(), 1); QCOMPARE(spyOnRowsInserted.count(), 0); QCOMPARE(spyOnCountChanged.count(), 1); arguments = spyOnRowsRemoved.takeFirst(); QCOMPARE(arguments.at(1).toInt(), 0); QCOMPARE(arguments.at(2).toInt(), 6); QCOMPARE(proxy.rowCount(), 0); } void testNestedProxyRoleNames() { QLimitProxyModelQML proxy1, proxy2; MockListModel model; QHash roles; roles[0] = "role0"; roles[1] = "role1"; model.setRoles(roles); proxy1.setModel(&model); proxy2.setModel(&proxy1); QCOMPARE(proxy2.roleNames(), model.roleNames()); } void testModelTest() { QLimitProxyModelQML proxy; MockListModel model; proxy.setModel(&model); proxy.setLimit(7); model.insertRows(0, 12); ModelTest t1(&proxy); } void testModelChanged() { QLimitProxyModelQML proxy; MockListModel model, model2; QSignalSpy spyOnModelChanged(&proxy, &QLimitProxyModelQML::modelChanged); proxy.setModel(&model); QCOMPARE(spyOnModelChanged.count(), 1); proxy.setModel(&model2); QCOMPARE(spyOnModelChanged.count(), 2); proxy.setModel(&model); QCOMPARE(spyOnModelChanged.count(), 3); proxy.setModel(&model); QCOMPARE(spyOnModelChanged.count(), 3); } void setSameModelTwice() { QLimitProxyModelQML proxy; MockListModel model; proxy.setModel(&model); proxy.setModel(&model); QSignalSpy spyOnCountChanged(&proxy, &QLimitProxyModelQML::countChanged); model.insertRows(0, 5); QCOMPARE(proxy.rowCount(), 5); QCOMPARE(spyOnCountChanged.count(), 1); } void testMirrorModel() { QLimitProxyModelQML proxy; MockListModel model; MirrorModel mirror(&proxy); proxy.setModel(&model); proxy.setLimit(5); // Checks what happens when the model already has // more items than the limit and we add stuff to // the front model.insertRows(0, 7); mirror.check(); model.insertRows(1, 3); mirror.check(); model.clear(); mirror.check(); // Checks what happens when the model does // not has more items than limit but adding // stuff to its front makes it go past the limit model.insertRows(0, 3); mirror.check(); model.insertRows(1, 3); mirror.check(); model.clear(); mirror.check(); // Checks what happens when the model does // not has more items than limit and adding // stuff to its front makes it not go past the limit model.insertRows(0, 1); mirror.check(); model.insertRows(1, 3); mirror.check(); model.clear(); mirror.check(); // Checks what happens when the model already has // more items than the limit and we remove stuff from // the front but it still has more than the limit model.insertRows(0, 10); mirror.check(); model.removeRows(1, 3); mirror.check(); model.clear(); mirror.check(); // Checks what happens when the model already has // more items than the limit and we remove stuff from // the front but it has less than the limit model.insertRows(0, 6); mirror.check(); model.removeRows(1, 3); mirror.check(); model.clear(); mirror.check(); // Checks what happens when the model has // less items than the limit and we remove stuff from // the front model.insertRows(0, 4); mirror.check(); model.removeRows(1, 3); mirror.check(); model.clear(); mirror.check(); } }; QTEST_GUILESS_MAIN(QLimitProxyModelTest) #include "QLimitProxyModelTest.moc"