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 <qtest.h>
30#include <QtTest/qsignalspy.h>
31#include <QQmlEngine>
32#include <QQmlComponent>
33#include <QTimer>
34#include <QQmlContext>
35#include <qqmlinfo.h>
36#include "../../shared/util.h"
37
38#include "attached.h"
39
40class tst_qqmlinfo : public QQmlDataTest
41{
42 Q_OBJECT
43public:
44 tst_qqmlinfo() {}
45
46private slots:
47 void qmlObject();
48 void nestedQmlObject();
49 void nestedComponent();
50 void nonQmlObject();
51 void nullObject();
52 void nonQmlContextedObject();
53 void types();
54 void chaining();
55 void messageTypes();
56 void component();
57 void attachedObject();
58
59private:
60 QQmlEngine engine;
61};
62
63void tst_qqmlinfo::qmlObject()
64{
65 QQmlComponent component(&engine, testFileUrl(fileName: "qmlObject.qml"));
66
67 QObject *object = component.create();
68 QVERIFY(object != nullptr);
69
70 QString message = component.url().toString() + ":3:1: QML QtObject: Test Message";
71 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
72 qmlInfo(me: object) << "Test Message";
73
74 QObject *nested = qvariant_cast<QObject *>(v: object->property(name: "nested"));
75 QVERIFY(nested != nullptr);
76
77 message = component.url().toString() + ":6:13: QML QtObject: Second Test Message";
78 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
79 qmlInfo(me: nested) << "Second Test Message";
80}
81
82void tst_qqmlinfo::nestedQmlObject()
83{
84 QQmlComponent component(&engine, testFileUrl(fileName: "nestedQmlObject.qml"));
85
86 QObject *object = component.create();
87 QVERIFY(object != nullptr);
88
89 QObject *nested = qvariant_cast<QObject *>(v: object->property(name: "nested"));
90 QVERIFY(nested != nullptr);
91 QObject *nested2 = qvariant_cast<QObject *>(v: object->property(name: "nested2"));
92 QVERIFY(nested2 != nullptr);
93
94 QString message = component.url().toString() + ":5:13: QML NestedObject: Outer Object";
95 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
96 qmlInfo(me: nested) << "Outer Object";
97
98 message = testFileUrl(fileName: "NestedObject.qml").toString() + ":6:14: QML QtObject: Inner Object";
99 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
100 qmlInfo(me: nested2) << "Inner Object";
101}
102
103void tst_qqmlinfo::nestedComponent()
104{
105 QQmlComponent component(&engine, testFileUrl(fileName: "NestedComponent.qml"));
106
107 QObject *object = component.create();
108 QVERIFY(object != nullptr);
109
110 QObject *nested = qvariant_cast<QObject *>(v: object->property(name: "nested"));
111 QVERIFY(nested != nullptr);
112 QObject *nested2 = qvariant_cast<QObject *>(v: object->property(name: "nested2"));
113 QVERIFY(nested2 != nullptr);
114
115 QString message = component.url().toString() + ":10:9: QML NestedObject: Complex Object";
116 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
117 qmlInfo(me: nested) << "Complex Object";
118
119 message = component.url().toString() + ":16:9: QML Image: Simple Object";
120 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
121 qmlInfo(me: nested2) << "Simple Object";
122}
123
124void tst_qqmlinfo::nonQmlObject()
125{
126 QObject object;
127 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: QML QtObject: Test Message");
128 qmlInfo(me: &object) << "Test Message";
129
130 QTimer nonQmlObject;
131 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: QML QTimer: Test Message");
132 qmlInfo(me: &nonQmlObject) << "Test Message";
133}
134
135void tst_qqmlinfo::nullObject()
136{
137 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: Null Object Test Message");
138 qmlInfo(me: nullptr) << "Null Object Test Message";
139}
140
141void tst_qqmlinfo::nonQmlContextedObject()
142{
143 QObject object;
144 QQmlContext context(&engine);
145 QQmlEngine::setContextForObject(&object, &context);
146 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: QML QtObject: Test Message");
147 qmlInfo(me: &object) << "Test Message";
148}
149
150void tst_qqmlinfo::types()
151{
152 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: false");
153 qmlInfo(me: nullptr) << false;
154
155 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: 1.1");
156 qmlInfo(me: nullptr) << 1.1;
157
158 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: 1.2");
159 qmlInfo(me: nullptr) << 1.2f;
160
161 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: 15");
162 qmlInfo(me: nullptr) << 15;
163
164 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: 'b'");
165 qmlInfo(me: nullptr) << QChar('b');
166
167 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: \"Qt\"");
168 qmlInfo(me: nullptr) << QByteArray("Qt");
169
170 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: true");
171 qmlInfo(me: nullptr) << bool(true);
172
173 //### do we actually want QUrl to show up in the output?
174 //### why the extra space at the end?
175 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: QUrl(\"http://www.qt-project.org\") ");
176 qmlInfo(me: nullptr) << QUrl("http://www.qt-project.org");
177
178 //### should this be quoted?
179 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: hello");
180 qmlInfo(me: nullptr) << QLatin1String("hello");
181
182 //### should this be quoted?
183 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: World");
184 QString str("Hello World");
185 QStringRef ref(&str, 6, 5);
186 qmlInfo(me: nullptr) << ref;
187
188 //### should this be quoted?
189 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: Quick");
190 qmlInfo(me: nullptr) << QString ("Quick");
191}
192
193void tst_qqmlinfo::chaining()
194{
195 QString str("Hello World");
196 QStringRef ref(&str, 6, 5);
197 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: false 1.1 1.2 15 hello 'b' World \"Qt\" true Quick QUrl(\"http://www.qt-project.org\") ");
198 qmlInfo(me: nullptr) << false << ' '
199 << 1.1 << ' '
200 << 1.2f << ' '
201 << 15 << ' '
202 << QLatin1String("hello") << ' '
203 << QChar('b') << ' '
204 << ref << ' '
205 << QByteArray("Qt") << ' '
206 << bool(true) << ' '
207 << QString ("Quick") << ' '
208 << QUrl("http://www.qt-project.org");
209}
210
211// Ensure that messages of different types are sent with the correct QtMsgType.
212void tst_qqmlinfo::messageTypes()
213{
214 QTest::ignoreMessage(type: QtDebugMsg, message: "<Unknown File>: debug");
215 qmlDebug(me: nullptr) << QLatin1String("debug");
216
217 QTest::ignoreMessage(type: QtInfoMsg, message: "<Unknown File>: info");
218 qmlInfo(me: nullptr) << QLatin1String("info");
219
220 QTest::ignoreMessage(type: QtWarningMsg, message: "<Unknown File>: warning");
221 qmlWarning(me: nullptr) << QLatin1String("warning");
222}
223
224void tst_qqmlinfo::component()
225{
226 QQmlComponent component(&engine, testFileUrl(fileName: "Component.qml"));
227 QScopedPointer<QObject> object(component.create());
228 QVERIFY(object != nullptr);
229 QQmlComponent *delegate = qobject_cast<QQmlComponent*>(object: object->property(name: "delegate").value<QObject*>());
230 QVERIFY(delegate);
231
232 QString message = component.url().toString() + ":4:34: QML Component: Delegate error";
233 QTest::ignoreMessage(type: QtInfoMsg, qPrintable(message));
234 qmlInfo(me: delegate) << "Delegate error";
235}
236
237Q_DECLARE_METATYPE(QList<QQmlError>)
238
239void tst_qqmlinfo::attachedObject()
240{
241 qRegisterMetaType<QList<QQmlError>>();
242
243 QQmlComponent component(&engine, testFileUrl(fileName: "AttachedObject.qml"));
244
245 QSignalSpy warningSpy(&engine, SIGNAL(warnings(const QList<QQmlError> &)));
246 QVERIFY(warningSpy.isValid());
247
248 const QString qmlBindingLoopMessage = "QML Rectangle: Binding loop detected for property \"width\"";
249 const QString qmlBindingLoopMessageFull = component.url().toString() + ":7:5: " + qmlBindingLoopMessage;
250 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(qmlBindingLoopMessageFull));
251
252 const QString cppBindingLoopMessage = "QML AttachedObject (parent or ancestor of Attached): Binding loop detected for property \"a\"";
253 const QString cppBindingLoopMessageFull = component.url().toString() + ":4:1: " + cppBindingLoopMessage;
254 QTest::ignoreMessage(type: QtWarningMsg, qPrintable(cppBindingLoopMessageFull));
255
256 QScopedPointer<QObject> object(component.create());
257 QVERIFY2(object != nullptr, qPrintable(component.errorString()));
258 QCOMPARE(warningSpy.count(), 2);
259
260 // The Attached C++ type has no QML engine since it was created in C++, so we should see its parent instead.
261 const auto cppWarnings = warningSpy.at(i: 0).first().value<QList<QQmlError>>();
262 QCOMPARE(cppWarnings.first().description(), cppBindingLoopMessage);
263
264 // The QML type has a QML engine, so we should see the normal message.
265 const auto qmlWarnings = warningSpy.at(i: 1).first().value<QList<QQmlError>>();
266 QCOMPARE(qmlWarnings.first().description(), qmlBindingLoopMessage);
267}
268
269QTEST_MAIN(tst_qqmlinfo)
270
271#include "tst_qqmlinfo.moc"
272

source code of qtdeclarative/tests/auto/qml/qqmlinfo/tst_qqmlinfo.cpp