/*
* 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"