1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite 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 "../shared/debugutil_p.h"
30#include "../shared/qqmldebugprocess_p.h"
31#include "../../../shared/util.h"
32
33#include <private/qqmldebugconnection_p.h>
34#include <private/qqmlinspectorclient_p.h>
35
36#include <QtTest/qtest.h>
37#include <QtTest/qsignalspy.h>
38#include <QtCore/qtimer.h>
39#include <QtCore/qdebug.h>
40#include <QtCore/qthread.h>
41#include <QtCore/qlibraryinfo.h>
42#include <QtNetwork/qhostaddress.h>
43
44class tst_QQmlInspector : public QQmlDebugTest
45{
46 Q_OBJECT
47
48private:
49 ConnectResult startQmlProcess(const QString &qmlFile, bool restrictMode = true);
50 void checkAnimationSpeed(int targetMillisPerDegree);
51 QList<QQmlDebugClient *> createClients() override;
52 QQmlDebugProcess *createProcess(const QString &executable) override;
53
54 QPointer<QQmlInspectorClient> m_client;
55 QPointer<QQmlInspectorResultRecipient> m_recipient;
56
57private slots:
58 void connect_data();
59 void connect();
60 void setAnimationSpeed();
61 void showAppOnTop();
62};
63
64QQmlDebugTest::ConnectResult tst_QQmlInspector::startQmlProcess(const QString &qmlFile,
65 bool restrictServices)
66{
67 return QQmlDebugTest::connectTo(executable: QLibraryInfo::location(QLibraryInfo::BinariesPath) + "/qml",
68 services: restrictServices ? QStringLiteral("QmlInspector") : QString(),
69 extraArgs: testFile(fileName: qmlFile), block: true);
70}
71
72void tst_QQmlInspector::checkAnimationSpeed(int targetMillisPerDegree)
73{
74 const QString markerString = QStringLiteral("ms/degrees");
75
76 // Funny things can happen with time and VMs. Also the change might take a while to propagate.
77 // Thus, we wait until we either have 3 passes or 3 failures in a row, or 10 loops have passed.
78
79 int numFailures = 0;
80 int numPasses = 0;
81
82 for (int i = 0; i < 10; ++i) {
83 QString output = m_process->output();
84 int position = output.length();
85 do {
86 QVERIFY(QQmlDebugTest::waitForSignal(m_process, SIGNAL(readyReadStandardOutput())));
87 output = m_process->output();
88 } while (!output.mid(position).contains(s: markerString));
89
90
91 QStringList words = output.split(sep: QLatin1Char(' '));
92 const int marker = words.lastIndexOf(t: markerString);
93 QVERIFY(marker > 1);
94 const double degrees = words[marker - 1].toDouble();
95 const int milliseconds = words[marker - 2].toInt();
96 const double millisecondsPerDegree = milliseconds / degrees;
97
98 if (millisecondsPerDegree > targetMillisPerDegree - 3
99 || millisecondsPerDegree < targetMillisPerDegree + 3) {
100 if (++numPasses == 3)
101 return; // pass
102 numFailures = 0;
103 } else {
104 QVERIFY2(++numFailures < 3,
105 QString("3 consecutive failures when checking for %1 milliseconds per degree")
106 .arg(targetMillisPerDegree).toLocal8Bit().constData());
107 numPasses = 0;
108 }
109 }
110
111 QFAIL(QString("Animation speed won't settle to %1 milliseconds per degree")
112 .arg(targetMillisPerDegree).toLocal8Bit().constData());
113}
114
115QList<QQmlDebugClient *> tst_QQmlInspector::createClients()
116{
117 m_client = new QQmlInspectorClient(m_connection);
118 m_recipient = new QQmlInspectorResultRecipient(m_client);
119 QObject::connect(sender: m_client.data(), signal: &QQmlInspectorClient::responseReceived,
120 receiver: m_recipient.data(), slot: &QQmlInspectorResultRecipient::recordResponse);
121 return QList<QQmlDebugClient *>({m_client});
122}
123
124QQmlDebugProcess *tst_QQmlInspector::createProcess(const QString &executable)
125{
126 QQmlDebugProcess *process = QQmlDebugTest::createProcess(executable);
127 // Make sure the animation timing is exact
128 process->addEnvironment(environment: QLatin1String("QSG_RENDER_LOOP=basic"));
129 return process;
130}
131
132void tst_QQmlInspector::connect_data()
133{
134 QTest::addColumn<QString>(name: "file");
135 QTest::addColumn<bool>(name: "restrictMode");
136 QTest::newRow(dataTag: "rectangle/unrestricted") << "qtquick2.qml" << false;
137 QTest::newRow(dataTag: "rectangle/restricted") << "qtquick2.qml" << true;
138 QTest::newRow(dataTag: "window/unrestricted") << "window.qml" << false;
139 QTest::newRow(dataTag: "window/restricted") << "window.qml" << true;
140}
141
142void tst_QQmlInspector::connect()
143{
144 QFETCH(QString, file);
145 QFETCH(bool, restrictMode);
146 QCOMPARE(startQmlProcess(file, restrictMode), ConnectSuccess);
147 QVERIFY(m_client);
148 QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
149
150 int requestId = m_client->setInspectToolEnabled(true);
151 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
152 QVERIFY(m_recipient->lastResult);
153
154 requestId = m_client->setInspectToolEnabled(false);
155 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
156 QVERIFY(m_recipient->lastResult);
157}
158
159void tst_QQmlInspector::showAppOnTop()
160{
161 QCOMPARE(startQmlProcess("qtquick2.qml"), ConnectSuccess);
162 QVERIFY(m_client);
163 QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
164
165 int requestId = m_client->setShowAppOnTop(true);
166 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
167 QVERIFY(m_recipient->lastResult);
168
169 requestId = m_client->setShowAppOnTop(false);
170 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
171 QVERIFY(m_recipient->lastResult);
172}
173
174void tst_QQmlInspector::setAnimationSpeed()
175{
176 QCOMPARE(startQmlProcess("qtquick2.qml"), ConnectSuccess);
177 QVERIFY(m_client);
178 QTRY_COMPARE(m_client->state(), QQmlDebugClient::Enabled);
179 checkAnimationSpeed(targetMillisPerDegree: 10);
180
181 int requestId = m_client->setAnimationSpeed(0.5);
182 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
183 QVERIFY(m_recipient->lastResult);
184 checkAnimationSpeed(targetMillisPerDegree: 5);
185
186 requestId = m_client->setAnimationSpeed(2.0);
187 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
188 QVERIFY(m_recipient->lastResult);
189 checkAnimationSpeed(targetMillisPerDegree: 20);
190
191 requestId = m_client->setAnimationSpeed(1.0);
192 QTRY_COMPARE(m_recipient->lastResponseId, requestId);
193 QVERIFY(m_recipient->lastResult);
194 checkAnimationSpeed(targetMillisPerDegree: 10);
195}
196
197QTEST_MAIN(tst_QQmlInspector)
198
199#include "tst_qqmlinspector.moc"
200

source code of qtdeclarative/tests/auto/qml/debugger/qqmlinspector/tst_qqmlinspector.cpp