blob: 60bb7b264222a71a8c81888fea6d8f31a3f76a55 [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2017 Ford Motor Company
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtRemoteObjects module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
** Commercial License Usage
** Licensees holding valid commercial Qt 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/QtTest>
#include <QModelIndex>
namespace {
inline bool compareIndices(const QModelIndex &lhs, const QModelIndex &rhs)
{
QModelIndex left = lhs;
QModelIndex right = rhs;
while (left.row() == right.row() && left.column() == right.column() && left.isValid() && right.isValid()) {
left = left.parent();
right = right.parent();
}
if (left.isValid() || right.isValid())
return false;
return true;
}
struct WaitForDataChanged
{
struct IndexPair
{
QModelIndex topLeft;
QModelIndex bottomRight;
};
WaitForDataChanged(const QVector<QModelIndex> &pending, QSignalSpy *spy) : m_pending(pending), m_spy(spy){}
bool wait()
{
Q_ASSERT(m_spy);
const int maxRuns = std::min(m_pending.size(), 100);
int runs = 0;
bool cancel = false;
while (!cancel) {
const int numSignals = m_spy->size();
for (int i = 0; i < numSignals; ++i) {
const QList<QVariant> &signal = m_spy->takeFirst();
IndexPair pair = extractPair(signal);
checkAndRemoveRange(pair.topLeft, pair.bottomRight);
cancel = m_pending.isEmpty();
}
if (!cancel)
m_spy->wait(50);
++runs;
if (runs >= maxRuns)
cancel = true;
}
return runs < maxRuns;
}
static IndexPair extractPair(const QList<QVariant> &signal)
{
IndexPair pair;
if (signal.size() != 3)
return pair;
const bool matchingTypes = signal[0].type() == QVariant::nameToType("QModelIndex")
&& signal[1].type() == QVariant::nameToType("QModelIndex")
&& signal[2].type() == QVariant::nameToType("QVector<int>");
if (!matchingTypes)
return pair;
const QModelIndex topLeft = signal[0].value<QModelIndex>();
const QModelIndex bottomRight = signal[1].value<QModelIndex>();
pair.topLeft = topLeft;
pair.bottomRight = bottomRight;
return pair;
}
void checkAndRemoveRange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
QVERIFY(topLeft.parent() == bottomRight.parent());
const auto isInRange = [topLeft, bottomRight] (const QModelIndex &pending) noexcept -> bool {
if (pending.isValid() && compareIndices(pending.parent(), topLeft.parent())) {
const bool fitLeft = topLeft.column() <= pending.column();
const bool fitRight = bottomRight.column() >= pending.column();
const bool fitTop = topLeft.row() <= pending.row();
const bool fitBottom = bottomRight.row() >= pending.row();
if (fitLeft && fitRight && fitTop && fitBottom)
return true;
}
return false;
};
m_pending.erase(std::remove_if(m_pending.begin(), m_pending.end(), isInRange),
m_pending.end());
}
QVector<QModelIndex> m_pending;
QSignalSpy *m_spy;
};
} // namespace