1/****************************************************************************
2**
3** Copyright (C) 2017 Ford Motor Company
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtRemoteObjects module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30#include <QModelIndex>
31
32// Helper class which can be used by tests for starting a task and
33// waiting for its completion. It takes care of running an event
34// loop while waiting, until finished() method is called (or the
35// timeout is reached).
36class WaitHelper : public QObject
37{
38 Q_OBJECT
39
40public:
41 WaitHelper() { m_promise.reportStarted(); }
42
43 ~WaitHelper()
44 {
45 if (m_promise.future().isRunning())
46 m_promise.reportFinished();
47 }
48
49 /*
50 Starts an event loop and waits until finish() method is called
51 or the timeout is reached.
52 */
53 bool wait(int timeout = 30000)
54 {
55 if (m_promise.future().isFinished())
56 return true;
57
58 QFutureWatcher<void> watcher;
59 QSignalSpy watcherSpy(&watcher, &QFutureWatcher<void>::finished);
60 watcher.setFuture(m_promise.future());
61 return watcherSpy.wait(timeout);
62 }
63
64protected:
65 /*
66 The derived classes need to call this method to stop waiting.
67 */
68 void finish() { m_promise.reportFinished(); }
69
70private:
71 QFutureInterface<void> m_promise;
72};
73
74namespace {
75
76inline bool compareIndices(const QModelIndex &lhs, const QModelIndex &rhs)
77{
78 QModelIndex left = lhs;
79 QModelIndex right = rhs;
80 while (left.row() == right.row() && left.column() == right.column() && left.isValid() && right.isValid()) {
81 left = left.parent();
82 right = right.parent();
83 }
84 if (left.isValid() || right.isValid())
85 return false;
86 return true;
87}
88
89struct WaitForDataChanged : public WaitHelper
90{
91 WaitForDataChanged(const QAbstractItemModel *model, const QVector<QModelIndex> &pending)
92 : WaitHelper(), m_model(model), m_pending(pending)
93 {
94 connect(sender: m_model, signal: &QAbstractItemModel::dataChanged, context: this,
95 slot: [this](const QModelIndex &topLeft, const QModelIndex &bottomRight,
96 const QVector<int> &roles) {
97 Q_UNUSED(roles)
98
99 checkAndRemoveRange(topLeft, bottomRight);
100 if (m_pending.isEmpty())
101 finish();
102 });
103 }
104
105 void checkAndRemoveRange(const QModelIndex &topLeft, const QModelIndex &bottomRight)
106 {
107 QVERIFY(topLeft.parent() == bottomRight.parent());
108 const auto isInRange = [topLeft, bottomRight] (const QModelIndex &pending) noexcept -> bool {
109 if (pending.isValid() && compareIndices(lhs: pending.parent(), rhs: topLeft.parent())) {
110 const bool fitLeft = topLeft.column() <= pending.column();
111 const bool fitRight = bottomRight.column() >= pending.column();
112 const bool fitTop = topLeft.row() <= pending.row();
113 const bool fitBottom = bottomRight.row() >= pending.row();
114 if (fitLeft && fitRight && fitTop && fitBottom)
115 return true;
116 }
117 return false;
118 };
119 m_pending.erase(begin: std::remove_if(first: m_pending.begin(), last: m_pending.end(), pred: isInRange),
120 end: m_pending.end());
121 }
122
123private:
124 const QAbstractItemModel *m_model = nullptr;
125 QVector<QModelIndex> m_pending;
126};
127
128} // namespace
129

source code of qtremoteobjects/tests/auto/shared/model_utilities.h