Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativecontext / tst_qdeclarativecontext.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <qtest.h>
43 #include <QDebug>
44 #include <QDeclarativeEngine>
45 #include <QDeclarativeContext>
46 #include <QDeclarativeComponent>
47 #include <QDeclarativeExpression>
48
49 #ifdef Q_OS_SYMBIAN
50 // In Symbian OS test data is located in applications private dir
51 #define SRCDIR "."
52 #endif
53
54 class tst_qdeclarativecontext : public QObject
55 {
56     Q_OBJECT
57 public:
58     tst_qdeclarativecontext() {}
59
60 private slots:
61     void baseUrl();
62     void resolvedUrl();
63     void engineMethod();
64     void parentContext();
65     void setContextProperty();
66     void setContextObject();
67     void destruction();
68     void idAsContextProperty();
69     void readOnlyContexts();
70
71 private:
72     QDeclarativeEngine engine;
73 };
74
75 void tst_qdeclarativecontext::baseUrl()
76 {
77     QDeclarativeContext ctxt(&engine);
78
79     QCOMPARE(ctxt.baseUrl(), QUrl());
80
81     ctxt.setBaseUrl(QUrl("http://www.nokia.com/"));
82
83     QCOMPARE(ctxt.baseUrl(), QUrl("http://www.nokia.com/"));
84 }
85
86 void tst_qdeclarativecontext::resolvedUrl()
87 {
88     // Relative to the component
89     {
90         QDeclarativeContext ctxt(&engine);
91         ctxt.setBaseUrl(QUrl("http://www.nokia.com/"));
92
93         QCOMPARE(ctxt.resolvedUrl(QUrl("main.qml")), QUrl("http://www.nokia.com/main.qml"));
94     }
95
96     // Relative to a parent
97     {
98         QDeclarativeContext ctxt(&engine);
99         ctxt.setBaseUrl(QUrl("http://www.nokia.com/"));
100
101         QDeclarativeContext ctxt2(&ctxt);
102         QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl("http://www.nokia.com/main2.qml"));
103     }
104
105     // Relative to the engine
106     {
107         QDeclarativeContext ctxt(&engine);
108         QCOMPARE(ctxt.resolvedUrl(QUrl("main.qml")), engine.baseUrl().resolved(QUrl("main.qml")));
109     }
110
111     // Relative to a deleted parent
112     {
113         QDeclarativeContext *ctxt = new QDeclarativeContext(&engine);
114         ctxt->setBaseUrl(QUrl("http://www.nokia.com/"));
115
116         QDeclarativeContext ctxt2(ctxt);
117         QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl("http://www.nokia.com/main2.qml"));
118
119         delete ctxt; ctxt = 0;
120
121         QCOMPARE(ctxt2.resolvedUrl(QUrl("main2.qml")), QUrl());
122     }
123
124     // Absolute
125     {
126         QDeclarativeContext ctxt(&engine);
127
128         QCOMPARE(ctxt.resolvedUrl(QUrl("http://www.nokia.com/main2.qml")), QUrl("http://www.nokia.com/main2.qml"));
129         QCOMPARE(ctxt.resolvedUrl(QUrl("file:///main2.qml")), QUrl("file:///main2.qml"));
130     }
131 }
132
133 void tst_qdeclarativecontext::engineMethod()
134 {
135     QDeclarativeEngine *engine = new QDeclarativeEngine;
136
137     QDeclarativeContext ctxt(engine);
138     QDeclarativeContext ctxt2(&ctxt);
139     QDeclarativeContext ctxt3(&ctxt2);
140     QDeclarativeContext ctxt4(&ctxt2);
141
142     QCOMPARE(ctxt.engine(), engine);
143     QCOMPARE(ctxt2.engine(), engine);
144     QCOMPARE(ctxt3.engine(), engine);
145     QCOMPARE(ctxt4.engine(), engine);
146
147     delete engine; engine = 0;
148
149     QCOMPARE(ctxt.engine(), engine);
150     QCOMPARE(ctxt2.engine(), engine);
151     QCOMPARE(ctxt3.engine(), engine);
152     QCOMPARE(ctxt4.engine(), engine);
153 }
154
155 void tst_qdeclarativecontext::parentContext()
156 {
157     QDeclarativeEngine *engine = new QDeclarativeEngine;
158
159     QCOMPARE(engine->rootContext()->parentContext(), (QDeclarativeContext *)0);
160
161     QDeclarativeContext *ctxt = new QDeclarativeContext(engine);
162     QDeclarativeContext *ctxt2 = new QDeclarativeContext(ctxt);
163     QDeclarativeContext *ctxt3 = new QDeclarativeContext(ctxt2);
164     QDeclarativeContext *ctxt4 = new QDeclarativeContext(ctxt2);
165     QDeclarativeContext *ctxt5 = new QDeclarativeContext(ctxt);
166     QDeclarativeContext *ctxt6 = new QDeclarativeContext(engine);
167     QDeclarativeContext *ctxt7 = new QDeclarativeContext(engine->rootContext());
168
169     QCOMPARE(ctxt->parentContext(), engine->rootContext());
170     QCOMPARE(ctxt2->parentContext(), ctxt);
171     QCOMPARE(ctxt3->parentContext(), ctxt2);
172     QCOMPARE(ctxt4->parentContext(), ctxt2);
173     QCOMPARE(ctxt5->parentContext(), ctxt);
174     QCOMPARE(ctxt6->parentContext(), engine->rootContext());
175     QCOMPARE(ctxt7->parentContext(), engine->rootContext());
176
177     delete ctxt2; ctxt2 = 0;
178
179     QCOMPARE(ctxt->parentContext(), engine->rootContext());
180     QCOMPARE(ctxt3->parentContext(), (QDeclarativeContext *)0);
181     QCOMPARE(ctxt4->parentContext(), (QDeclarativeContext *)0);
182     QCOMPARE(ctxt5->parentContext(), ctxt);
183     QCOMPARE(ctxt6->parentContext(), engine->rootContext());
184     QCOMPARE(ctxt7->parentContext(), engine->rootContext());
185
186     delete engine; engine = 0;
187
188     QCOMPARE(ctxt->parentContext(), (QDeclarativeContext *)0);
189     QCOMPARE(ctxt3->parentContext(), (QDeclarativeContext *)0);
190     QCOMPARE(ctxt4->parentContext(), (QDeclarativeContext *)0);
191     QCOMPARE(ctxt5->parentContext(), (QDeclarativeContext *)0);
192     QCOMPARE(ctxt6->parentContext(), (QDeclarativeContext *)0);
193     QCOMPARE(ctxt7->parentContext(), (QDeclarativeContext *)0);
194
195     delete ctxt7;
196     delete ctxt6;
197     delete ctxt5;
198     delete ctxt4;
199     delete ctxt3;
200     delete ctxt;
201 }
202
203 class TestObject : public QObject
204 {
205     Q_OBJECT
206     Q_PROPERTY(int a READ a NOTIFY aChanged)
207     Q_PROPERTY(int b READ b NOTIFY bChanged)
208     Q_PROPERTY(int c READ c NOTIFY cChanged)
209
210 public:
211     TestObject() : _a(10), _b(10), _c(10) {}
212
213     int a() const { return _a; }
214     void setA(int a) { _a = a; emit aChanged(); }
215
216     int b() const { return _b; }
217     void setB(int b) { _b = b; emit bChanged(); }
218
219     int c() const { return _c; }
220     void setC(int c) { _c = c; emit cChanged(); }
221
222 signals:
223     void aChanged();
224     void bChanged();
225     void cChanged();
226
227 private:
228     int _a;
229     int _b;
230     int _c;
231 };
232
233 #define TEST_CONTEXT_PROPERTY(ctxt, name, value) \
234 { \
235     QDeclarativeComponent component(&engine); \
236     component.setData("import QtQuick 1.0; QtObject { property variant test: " #name " }", QUrl()); \
237 \
238     QObject *obj = component.create(ctxt); \
239 \
240     QCOMPARE(obj->property("test"), value); \
241 \
242     delete obj; \
243
244
245 void tst_qdeclarativecontext::setContextProperty()
246 {
247     QDeclarativeContext ctxt(&engine);
248     QDeclarativeContext ctxt2(&ctxt);
249
250     TestObject obj1;
251     obj1.setA(3345);
252     TestObject obj2;
253     obj2.setA(-19);
254
255     // Static context properties
256     ctxt.setContextProperty("a", QVariant(10));
257     ctxt.setContextProperty("b", QVariant(9));
258     ctxt2.setContextProperty("d", &obj2);
259     ctxt2.setContextProperty("b", QVariant(19));
260     ctxt2.setContextProperty("c", QVariant(QString("Hello World!")));
261     ctxt.setContextProperty("d", &obj1);
262     ctxt.setContextProperty("e", &obj1);
263
264     TEST_CONTEXT_PROPERTY(&ctxt2, a, QVariant(10));
265     TEST_CONTEXT_PROPERTY(&ctxt2, b, QVariant(19));
266     TEST_CONTEXT_PROPERTY(&ctxt2, c, QVariant(QString("Hello World!")));
267     TEST_CONTEXT_PROPERTY(&ctxt2, d.a, QVariant(-19));
268     TEST_CONTEXT_PROPERTY(&ctxt2, e.a, QVariant(3345));
269
270     ctxt.setContextProperty("a", QVariant(13));
271     ctxt.setContextProperty("b", QVariant(4));
272     ctxt2.setContextProperty("b", QVariant(8));
273     ctxt2.setContextProperty("c", QVariant(QString("Hi World!")));
274     ctxt2.setContextProperty("d", &obj1);
275     obj1.setA(12);
276
277     TEST_CONTEXT_PROPERTY(&ctxt2, a, QVariant(13));
278     TEST_CONTEXT_PROPERTY(&ctxt2, b, QVariant(8));
279     TEST_CONTEXT_PROPERTY(&ctxt2, c, QVariant(QString("Hi World!")));
280     TEST_CONTEXT_PROPERTY(&ctxt2, d.a, QVariant(12));
281     TEST_CONTEXT_PROPERTY(&ctxt2, e.a, QVariant(12));
282
283     // Changes in context properties
284     {
285         QDeclarativeComponent component(&engine); 
286         component.setData("import QtQuick 1.0; QtObject { property variant test: a }", QUrl());
287
288         QObject *obj = component.create(&ctxt2); 
289
290         QCOMPARE(obj->property("test"), QVariant(13)); 
291         ctxt.setContextProperty("a", QVariant(19));
292         QCOMPARE(obj->property("test"), QVariant(19)); 
293
294         delete obj; 
295     }
296     {
297         QDeclarativeComponent component(&engine); 
298         component.setData("import QtQuick 1.0; QtObject { property variant test: b }", QUrl());
299
300         QObject *obj = component.create(&ctxt2); 
301
302         QCOMPARE(obj->property("test"), QVariant(8)); 
303         ctxt.setContextProperty("b", QVariant(5));
304         QCOMPARE(obj->property("test"), QVariant(8)); 
305         ctxt2.setContextProperty("b", QVariant(1912));
306         QCOMPARE(obj->property("test"), QVariant(1912)); 
307
308         delete obj; 
309     }
310     {
311         QDeclarativeComponent component(&engine); 
312         component.setData("import QtQuick 1.0; QtObject { property variant test: e.a }", QUrl());
313
314         QObject *obj = component.create(&ctxt2); 
315
316         QCOMPARE(obj->property("test"), QVariant(12)); 
317         obj1.setA(13);
318         QCOMPARE(obj->property("test"), QVariant(13)); 
319
320         delete obj; 
321     }
322
323     // New context properties
324     {
325         QDeclarativeComponent component(&engine); 
326         component.setData("import QtQuick 1.0; QtObject { property variant test: a }", QUrl());
327
328         QObject *obj = component.create(&ctxt2); 
329
330         QCOMPARE(obj->property("test"), QVariant(19)); 
331         ctxt2.setContextProperty("a", QVariant(1945));
332         QCOMPARE(obj->property("test"), QVariant(1945)); 
333
334         delete obj; 
335     }
336
337     // Setting an object-variant context property
338     {
339         QDeclarativeComponent component(&engine);
340         component.setData("import QtQuick 1.0; QtObject { id: root; property int a: 10; property int test: ctxtProp.a; property variant obj: root; }", QUrl());
341
342         QDeclarativeContext ctxt(engine.rootContext());
343         ctxt.setContextProperty("ctxtProp", QVariant());
344
345         QTest::ignoreMessage(QtWarningMsg, "<Unknown File>:1: TypeError: Result of expression 'ctxtProp' [undefined] is not an object.");
346         QObject *obj = component.create(&ctxt);
347
348         QVariant v = obj->property("obj");
349
350         ctxt.setContextProperty("ctxtProp", v);
351
352         QCOMPARE(obj->property("test"), QVariant(10));
353
354         delete obj;
355     }
356 }
357
358 void tst_qdeclarativecontext::setContextObject()
359 {
360     QDeclarativeContext ctxt(&engine);
361
362     TestObject to;
363
364     to.setA(2);
365     to.setB(192);
366     to.setC(18);
367
368     ctxt.setContextObject(&to);
369     ctxt.setContextProperty("c", QVariant(9));
370
371     // Static context properties
372     TEST_CONTEXT_PROPERTY(&ctxt, a, QVariant(2));
373     TEST_CONTEXT_PROPERTY(&ctxt, b, QVariant(192));
374     TEST_CONTEXT_PROPERTY(&ctxt, c, QVariant(9));
375
376     to.setA(12);
377     to.setB(100);
378     to.setC(7);
379     ctxt.setContextProperty("c", QVariant(3));
380
381     TEST_CONTEXT_PROPERTY(&ctxt, a, QVariant(12));
382     TEST_CONTEXT_PROPERTY(&ctxt, b, QVariant(100));
383     TEST_CONTEXT_PROPERTY(&ctxt, c, QVariant(3));
384
385     // Changes in context properties
386     {
387         QDeclarativeComponent component(&engine); 
388         component.setData("import QtQuick 1.0; QtObject { property variant test: a }", QUrl());
389
390         QObject *obj = component.create(&ctxt); 
391
392         QCOMPARE(obj->property("test"), QVariant(12)); 
393         to.setA(14);
394         QCOMPARE(obj->property("test"), QVariant(14)); 
395
396         delete obj; 
397     }
398 }
399
400 void tst_qdeclarativecontext::destruction()
401 {
402     QDeclarativeContext *ctxt = new QDeclarativeContext(&engine);
403
404     QObject obj;
405     QDeclarativeEngine::setContextForObject(&obj, ctxt);
406     QDeclarativeExpression expr(ctxt, 0, "a");
407
408     QCOMPARE(ctxt, QDeclarativeEngine::contextForObject(&obj));
409     QCOMPARE(ctxt, expr.context());
410
411     delete ctxt; ctxt = 0;
412
413     QCOMPARE(ctxt, QDeclarativeEngine::contextForObject(&obj));
414     QCOMPARE(ctxt, expr.context());
415 }
416
417 void tst_qdeclarativecontext::idAsContextProperty()
418 {
419     QDeclarativeComponent component(&engine);
420     component.setData("import QtQuick 1.0; QtObject { property variant a; a: QtObject { id: myObject } }", QUrl());
421
422     QObject *obj = component.create();
423     QVERIFY(obj);
424
425     QVariant a = obj->property("a");
426     QVERIFY(a.userType() == QMetaType::QObjectStar);
427
428     QVariant ctxt = qmlContext(obj)->contextProperty("myObject");
429     QVERIFY(ctxt.userType() == QMetaType::QObjectStar);
430
431     QVERIFY(a == ctxt);
432
433     delete obj;
434 }
435
436 // Internal contexts should be read-only
437 void tst_qdeclarativecontext::readOnlyContexts()
438 {
439     QDeclarativeComponent component(&engine);
440     component.setData("import QtQuick 1.0; QtObject { id: me }", QUrl());
441
442     QObject *obj = component.create();
443     QVERIFY(obj);
444
445     QDeclarativeContext *context = qmlContext(obj);
446     QVERIFY(context);
447
448     QVERIFY(qvariant_cast<QObject*>(context->contextProperty("me")) == obj);
449     QVERIFY(context->contextObject() == obj);
450
451     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeContext: Cannot set property on internal context.");
452     context->setContextProperty("hello", 12);
453     QVERIFY(context->contextProperty("hello") == QVariant());
454
455     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeContext: Cannot set property on internal context.");
456     context->setContextProperty("hello", obj);
457     QVERIFY(context->contextProperty("hello") == QVariant());
458
459     QTest::ignoreMessage(QtWarningMsg, "QDeclarativeContext: Cannot set context object for internal context.");
460     context->setContextObject(0);
461     QVERIFY(context->contextObject() == obj);
462
463     delete obj;
464 }
465
466 QTEST_MAIN(tst_qdeclarativecontext)
467
468 #include "tst_qdeclarativecontext.moc"