39dac6f50e018cf3247d6ff6c662af0092cca882
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativestates / tst_qdeclarativestates.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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QtDeclarative/qdeclarativeengine.h>
43 #include <QtDeclarative/qdeclarativecomponent.h>
44 #include <QtDeclarative/qsgview.h>
45 #include <private/qsgstateoperations_p.h>
46 #include <private/qsganchors_p_p.h>
47 #include <private/qsgrectangle_p.h>
48 #include <private/qsgimage_p.h>
49 #include <private/qdeclarativepropertychanges_p.h>
50 #include <private/qdeclarativestategroup_p.h>
51 #include <private/qsgitem_p.h>
52 #include <private/qdeclarativeproperty_p.h>
53 #include "../../../shared/util.h"
54
55 class MyAttached : public QObject
56 {
57     Q_OBJECT
58     Q_PROPERTY(int foo READ foo WRITE setFoo)
59 public:
60     MyAttached(QObject *parent) : QObject(parent), m_foo(13) {}
61
62     int foo() const { return m_foo; }
63     void setFoo(int f) { m_foo = f; }
64
65 private:
66     int m_foo;
67 };
68
69 class MyRect : public QSGRectangle
70 {
71    Q_OBJECT
72    Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal)
73 public:
74     MyRect() {}
75
76     void doSomething() { emit didSomething(); }
77     
78     int propertyWithNotify() const { return m_prop; }
79     void setPropertyWithNotify(int i) { m_prop = i; emit oddlyNamedNotifySignal(); }
80
81     static MyAttached *qmlAttachedProperties(QObject *o) {
82         return new MyAttached(o);
83     }
84 Q_SIGNALS:
85     void didSomething();
86     void oddlyNamedNotifySignal();
87
88 private:
89     int m_prop;
90 };
91
92 QML_DECLARE_TYPE(MyRect)
93 QML_DECLARE_TYPEINFO(MyRect, QML_HAS_ATTACHED_PROPERTIES)
94
95 class tst_qdeclarativestates : public QObject
96 {
97     Q_OBJECT
98 public:
99     tst_qdeclarativestates() {}
100
101 private:
102     static QByteArray fullDataPath(const QString &path);
103
104 private slots:
105     void initTestCase();
106
107     void basicChanges();
108     void attachedPropertyChanges();
109     void basicExtension();
110     void basicBinding();
111     void signalOverride();
112     void signalOverrideCrash();
113     void signalOverrideCrash2();
114     void parentChange();
115     void parentChangeErrors();
116     void anchorChanges();
117     void anchorChanges2();
118     void anchorChanges3();
119     void anchorChanges4();
120     void anchorChanges5();
121     void anchorChangesRTL();
122     void anchorChangesRTL2();
123     void anchorChangesRTL3();
124     void anchorChangesCrash();
125     void anchorRewindBug();
126     void anchorRewindBug2();
127     void script();
128     void restoreEntryValues();
129     void explicitChanges();
130     void propertyErrors();
131     void incorrectRestoreBug();
132     void autoStateAtStartupRestoreBug();
133     void deletingChange();
134     void deletingState();
135     void tempState();
136     void illegalTempState();
137     void nonExistantProperty();
138     void reset();
139     void illegalObjectCreation();
140     void whenOrdering();
141     void urlResolution();
142     void unnamedWhen();
143     void returnToBase();
144     void extendsBug();
145     void editProperties();
146     void QTBUG_14830();
147     void avoidFastForward();
148 };
149
150 void tst_qdeclarativestates::initTestCase()
151 {
152     qmlRegisterType<MyRect>("Qt.test", 1, 0, "MyRectangle");
153 }
154
155 QByteArray tst_qdeclarativestates::fullDataPath(const QString &path)
156 {
157     return QUrl::fromLocalFile(SRCDIR + path).toString().toUtf8();    
158 }
159
160 void tst_qdeclarativestates::basicChanges()
161 {
162     QDeclarativeEngine engine;
163
164     {
165         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges.qml");
166         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
167         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
168         QVERIFY(rect != 0);
169
170         QCOMPARE(rect->color(),QColor("red"));
171
172         rectPrivate->setState("blue");
173         QCOMPARE(rect->color(),QColor("blue"));
174
175         rectPrivate->setState("");
176         QCOMPARE(rect->color(),QColor("red"));
177     }
178
179     {
180         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges2.qml");
181         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
182         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
183         QVERIFY(rect != 0);
184
185         QCOMPARE(rect->color(),QColor("red"));
186
187         rectPrivate->setState("blue");
188         QCOMPARE(rect->color(),QColor("blue"));
189
190         rectPrivate->setState("green");
191         QCOMPARE(rect->color(),QColor("green"));
192
193         rectPrivate->setState("");
194         QCOMPARE(rect->color(),QColor("red"));
195
196         rectPrivate->setState("green");
197         QCOMPARE(rect->color(),QColor("green"));
198     }
199
200     {
201         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges3.qml");
202         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
203         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
204         QVERIFY(rect != 0);
205
206         QCOMPARE(rect->color(),QColor("red"));
207         QCOMPARE(rect->border()->width(),1.0);
208
209         rectPrivate->setState("blue");
210         QCOMPARE(rect->color(),QColor("blue"));
211         QCOMPARE(rect->border()->width(),1.0);
212
213         rectPrivate->setState("bordered");
214         QCOMPARE(rect->color(),QColor("red"));
215         QCOMPARE(rect->border()->width(),2.0);
216
217         rectPrivate->setState("");
218         QCOMPARE(rect->color(),QColor("red"));
219         QCOMPARE(rect->border()->width(),1.0);
220         //### we should be checking that this is an implicit rather than explicit 1 (which currently fails)
221
222         rectPrivate->setState("bordered");
223         QCOMPARE(rect->color(),QColor("red"));
224         QCOMPARE(rect->border()->width(),2.0);
225
226         rectPrivate->setState("blue");
227         QCOMPARE(rect->color(),QColor("blue"));
228         QCOMPARE(rect->border()->width(),1.0);
229
230     }
231
232     {
233         // Test basicChanges4.qml can magically connect to propertyWithNotify's notify
234         // signal using 'onPropertyWithNotifyChanged' even though the signal name is
235         // actually 'oddlyNamedNotifySignal'
236
237         QDeclarativeComponent component(&engine, SRCDIR "/data/basicChanges4.qml");
238         QVERIFY(component.isReady());
239
240         MyRect *rect = qobject_cast<MyRect*>(component.create());
241         QVERIFY(rect != 0);
242
243         QMetaProperty prop = rect->metaObject()->property(rect->metaObject()->indexOfProperty("propertyWithNotify"));
244         QVERIFY(prop.hasNotifySignal());
245         QString notifySignal = QByteArray(prop.notifySignal().signature());
246         QVERIFY(!notifySignal.startsWith("propertyWithNotifyChanged("));
247
248         QCOMPARE(rect->color(), QColor(Qt::red));
249
250         rect->setPropertyWithNotify(100);
251         QCOMPARE(rect->color(), QColor(Qt::blue));
252     }
253 }
254
255 void tst_qdeclarativestates::attachedPropertyChanges()
256 {
257     QDeclarativeEngine engine;
258
259     QDeclarativeComponent component(&engine, SRCDIR "/data/attachedPropertyChanges.qml");
260     QVERIFY(component.isReady());
261
262     QSGItem *item = qobject_cast<QSGItem*>(component.create());
263     QVERIFY(item != 0);
264     QCOMPARE(item->width(), 50.0);
265
266     // Ensure attached property has been changed
267     QObject *attObj = qmlAttachedPropertiesObject<MyRect>(item, false);
268     QVERIFY(attObj);
269
270     MyAttached *att = qobject_cast<MyAttached*>(attObj);
271     QVERIFY(att);
272
273     QCOMPARE(att->foo(), 1);
274 }
275
276 void tst_qdeclarativestates::basicExtension()
277 {
278     QDeclarativeEngine engine;
279
280     {
281         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicExtension.qml");
282         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
283         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
284         QVERIFY(rect != 0);
285
286         QCOMPARE(rect->color(),QColor("red"));
287         QCOMPARE(rect->border()->width(),1.0);
288
289         rectPrivate->setState("blue");
290         QCOMPARE(rect->color(),QColor("blue"));
291         QCOMPARE(rect->border()->width(),1.0);
292
293         rectPrivate->setState("bordered");
294         QCOMPARE(rect->color(),QColor("blue"));
295         QCOMPARE(rect->border()->width(),2.0);
296
297         rectPrivate->setState("blue");
298         QCOMPARE(rect->color(),QColor("blue"));
299         QCOMPARE(rect->border()->width(),1.0);
300
301         rectPrivate->setState("");
302         QCOMPARE(rect->color(),QColor("red"));
303         QCOMPARE(rect->border()->width(),1.0);
304
305         rectPrivate->setState("bordered");
306         QCOMPARE(rect->color(),QColor("blue"));
307         QCOMPARE(rect->border()->width(),2.0);
308
309         rectPrivate->setState("");
310         QCOMPARE(rect->color(),QColor("red"));
311         QCOMPARE(rect->border()->width(),1.0);
312     }
313
314     {
315         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/fakeExtension.qml");
316         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
317         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
318         QVERIFY(rect != 0);
319
320         QCOMPARE(rect->color(),QColor("red"));
321
322         rectPrivate->setState("blue");
323         QCOMPARE(rect->color(),QColor("blue"));
324
325         rectPrivate->setState("green");
326         QCOMPARE(rect->color(),QColor("green"));
327
328         rectPrivate->setState("blue");
329         QCOMPARE(rect->color(),QColor("blue"));
330
331         rectPrivate->setState("green");
332         QCOMPARE(rect->color(),QColor("green"));
333
334         rectPrivate->setState("");
335         QCOMPARE(rect->color(),QColor("red"));
336
337         rectPrivate->setState("green");
338         QCOMPARE(rect->color(),QColor("green"));
339     }
340 }
341
342 void tst_qdeclarativestates::basicBinding()
343 {
344     QDeclarativeEngine engine;
345
346     {
347         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding.qml");
348         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
349         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
350         QVERIFY(rect != 0);
351
352         QCOMPARE(rect->color(),QColor("red"));
353
354         rectPrivate->setState("blue");
355         QCOMPARE(rect->color(),QColor("blue"));
356
357         rectPrivate->setState("");
358         QCOMPARE(rect->color(),QColor("red"));
359
360         rectPrivate->setState("blue");
361         QCOMPARE(rect->color(),QColor("blue"));
362         rect->setProperty("sourceColor", QColor("green"));
363         QCOMPARE(rect->color(),QColor("green"));
364
365         rectPrivate->setState("");
366         QCOMPARE(rect->color(),QColor("red"));
367         rect->setProperty("sourceColor", QColor("yellow"));
368         QCOMPARE(rect->color(),QColor("red"));
369
370         rectPrivate->setState("blue");
371         QCOMPARE(rect->color(),QColor("yellow"));
372     }
373
374     {
375         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding2.qml");
376         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
377         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
378         QVERIFY(rect != 0);
379
380         QCOMPARE(rect->color(),QColor("red"));
381
382         rectPrivate->setState("blue");
383         QCOMPARE(rect->color(),QColor("blue"));
384
385         rectPrivate->setState("");
386         QCOMPARE(rect->color(),QColor("red"));
387
388         rectPrivate->setState("blue");
389         QCOMPARE(rect->color(),QColor("blue"));
390         rect->setProperty("sourceColor", QColor("green"));
391         QCOMPARE(rect->color(),QColor("blue"));
392
393         rectPrivate->setState("");
394         QCOMPARE(rect->color(),QColor("green"));
395         rect->setProperty("sourceColor", QColor("yellow"));
396         QCOMPARE(rect->color(),QColor("yellow"));
397
398         rectPrivate->setState("blue");
399         QCOMPARE(rect->color(),QColor("blue"));
400
401         rectPrivate->setState("");
402         QCOMPARE(rect->color(),QColor("yellow"));
403     }
404
405     {
406         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding3.qml");
407         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
408         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
409         QVERIFY(rect != 0);
410
411         QCOMPARE(rect->color(),QColor("red"));
412         rect->setProperty("sourceColor", QColor("green"));
413         QCOMPARE(rect->color(),QColor("green"));
414
415         rectPrivate->setState("blue");
416         QCOMPARE(rect->color(),QColor("blue"));
417         rect->setProperty("sourceColor", QColor("red"));
418         QCOMPARE(rect->color(),QColor("blue"));
419         rect->setProperty("sourceColor2", QColor("yellow"));
420         QCOMPARE(rect->color(),QColor("yellow"));
421
422         rectPrivate->setState("");
423         QCOMPARE(rect->color(),QColor("red"));
424         rect->setProperty("sourceColor2", QColor("green"));
425         QCOMPARE(rect->color(),QColor("red"));
426         rect->setProperty("sourceColor", QColor("yellow"));
427         QCOMPARE(rect->color(),QColor("yellow"));
428     }
429
430     {
431         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding4.qml");
432         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
433         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
434         QVERIFY(rect != 0);
435
436         QCOMPARE(rect->color(),QColor("red"));
437
438         rectPrivate->setState("blue");
439         QCOMPARE(rect->color(),QColor("blue"));
440         rect->setProperty("sourceColor", QColor("yellow"));
441         QCOMPARE(rect->color(),QColor("yellow"));
442
443         rectPrivate->setState("green");
444         QCOMPARE(rect->color(),QColor("green"));
445         rect->setProperty("sourceColor", QColor("purple"));
446         QCOMPARE(rect->color(),QColor("green"));
447
448         rectPrivate->setState("blue");
449         QCOMPARE(rect->color(),QColor("purple"));
450
451         rectPrivate->setState("green");
452         QCOMPARE(rect->color(),QColor("green"));
453
454         rectPrivate->setState("");
455         QCOMPARE(rect->color(),QColor("red"));
456     }
457 }
458
459 void tst_qdeclarativestates::signalOverride()
460 {
461     QDeclarativeEngine engine;
462
463     {
464         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverride.qml");
465         MyRect *rect = qobject_cast<MyRect*>(rectComponent.create());
466         QVERIFY(rect != 0);
467
468         QCOMPARE(rect->color(),QColor("red"));
469         rect->doSomething();
470         QCOMPARE(rect->color(),QColor("blue"));
471
472         QSGItemPrivate::get(rect)->setState("green");
473         rect->doSomething();
474         QCOMPARE(rect->color(),QColor("green"));
475     }
476
477     {
478         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverride2.qml");
479         MyRect *rect = qobject_cast<MyRect*>(rectComponent.create());
480         QVERIFY(rect != 0);
481
482         QCOMPARE(rect->color(),QColor("white"));
483         rect->doSomething();
484         QCOMPARE(rect->color(),QColor("blue"));
485
486         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("extendedRect"));
487         QSGItemPrivate::get(innerRect)->setState("green");
488         rect->doSomething();
489         QCOMPARE(rect->color(),QColor("blue"));
490         QCOMPARE(innerRect->color(),QColor("green"));
491         QCOMPARE(innerRect->property("extendedColor").value<QColor>(),QColor("green"));
492     }
493 }
494
495 void tst_qdeclarativestates::signalOverrideCrash()
496 {
497     QDeclarativeEngine engine;
498
499     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverrideCrash.qml");
500     MyRect *rect = qobject_cast<MyRect*>(rectComponent.create());
501     QVERIFY(rect != 0);
502
503     QSGItemPrivate::get(rect)->setState("overridden");
504     rect->doSomething();
505 }
506
507 void tst_qdeclarativestates::signalOverrideCrash2()
508 {
509     QDeclarativeEngine engine;
510
511     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverrideCrash2.qml");
512     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
513     QVERIFY(rect != 0);
514
515     QSGItemPrivate::get(rect)->setState("state1");
516     QSGItemPrivate::get(rect)->setState("state2");
517     QSGItemPrivate::get(rect)->setState("state1");
518
519     delete rect;
520 }
521
522 void tst_qdeclarativestates::parentChange()
523 {
524     QDeclarativeEngine engine;
525
526     {
527         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange1.qml");
528         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
529         QVERIFY(rect != 0);
530
531         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
532         QVERIFY(innerRect != 0);
533
534         QDeclarativeListReference list(rect, "states");
535         QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
536         QVERIFY(state != 0);
537
538         qmlExecuteDeferred(state);
539         QSGParentChange *pChange = qobject_cast<QSGParentChange*>(state->operationAt(0));
540         QVERIFY(pChange != 0);
541         QSGItem *nParent = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("NewParent"));
542         QVERIFY(nParent != 0);
543
544         QCOMPARE(pChange->parent(), nParent);
545
546         QSGItemPrivate::get(rect)->setState("reparented");
547         QCOMPARE(innerRect->rotation(), qreal(0));
548         QCOMPARE(innerRect->scale(), qreal(1));
549         QCOMPARE(innerRect->x(), qreal(-133));
550         QCOMPARE(innerRect->y(), qreal(-300));
551     }
552
553     {
554         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange2.qml");
555         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
556         QVERIFY(rect != 0);
557         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
558         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
559         QVERIFY(innerRect != 0);
560
561         rectPrivate->setState("reparented");
562         QCOMPARE(innerRect->rotation(), qreal(15));
563         QCOMPARE(innerRect->scale(), qreal(.5));
564         QCOMPARE(QString("%1").arg(innerRect->x()), QString("%1").arg(-19.9075));
565         QCOMPARE(QString("%1").arg(innerRect->y()), QString("%1").arg(-8.73433));
566     }
567
568     {
569         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange3.qml");
570         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
571         QVERIFY(rect != 0);
572         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
573         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
574         QVERIFY(innerRect != 0);
575
576         rectPrivate->setState("reparented");
577         QCOMPARE(innerRect->rotation(), qreal(-37));
578         QCOMPARE(innerRect->scale(), qreal(.25));
579         QCOMPARE(QString("%1").arg(innerRect->x()), QString("%1").arg(-217.305));
580         QCOMPARE(QString("%1").arg(innerRect->y()), QString("%1").arg(-164.413));
581
582         rectPrivate->setState("");
583         QCOMPARE(innerRect->rotation(), qreal(0));
584         QCOMPARE(innerRect->scale(), qreal(1));
585         QCOMPARE(innerRect->x(), qreal(5));
586         //do a non-qFuzzyCompare fuzzy compare
587         QVERIFY(innerRect->y() < qreal(0.00001) && innerRect->y() > qreal(-0.00001));
588     }
589
590     {
591         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange6.qml");
592         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
593         QVERIFY(rect != 0);
594
595         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
596         QVERIFY(innerRect != 0);
597
598         QSGItemPrivate::get(rect)->setState("reparented");
599         QCOMPARE(innerRect->rotation(), qreal(180));
600         QCOMPARE(innerRect->scale(), qreal(1));
601         QCOMPARE(innerRect->x(), qreal(-105));
602         QCOMPARE(innerRect->y(), qreal(-105));
603     }
604 }
605
606 void tst_qdeclarativestates::parentChangeErrors()
607 {
608     QDeclarativeEngine engine;
609
610     {
611         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange4.qml");
612         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
613         QVERIFY(rect != 0);
614
615         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
616         QVERIFY(innerRect != 0);
617
618         QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/parentChange4.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under non-uniform scale");
619         QSGItemPrivate::get(rect)->setState("reparented");
620         QCOMPARE(innerRect->rotation(), qreal(0));
621         QCOMPARE(innerRect->scale(), qreal(1));
622         QCOMPARE(innerRect->x(), qreal(5));
623         QCOMPARE(innerRect->y(), qreal(5));
624     }
625
626     {
627         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange5.qml");
628         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
629         QVERIFY(rect != 0);
630
631         QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
632         QVERIFY(innerRect != 0);
633
634         QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/parentChange5.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under complex transform");
635         QSGItemPrivate::get(rect)->setState("reparented");
636         QCOMPARE(innerRect->rotation(), qreal(0));
637         QCOMPARE(innerRect->scale(), qreal(1));
638         QCOMPARE(innerRect->x(), qreal(5));
639         QCOMPARE(innerRect->y(), qreal(5));
640     }
641 }
642
643 void tst_qdeclarativestates::anchorChanges()
644 {
645     QDeclarativeEngine engine;
646
647     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges1.qml");
648     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
649     QVERIFY(rect != 0);
650     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
651
652     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
653     QVERIFY(innerRect != 0);
654
655     QDeclarativeListReference list(rect, "states");
656     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
657     QVERIFY(state != 0);
658
659     qmlExecuteDeferred(state);
660     QSGAnchorChanges *aChanges = qobject_cast<QSGAnchorChanges*>(state->operationAt(0));
661     QVERIFY(aChanges != 0);
662
663     rectPrivate->setState("right");
664     QCOMPARE(innerRect->x(), qreal(150));
665     QCOMPARE(aChanges->object(), qobject_cast<QSGItem*>(innerRect));
666     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QSGAnchorLine::Invalid);  //### was reset (how do we distinguish from not set at all)
667     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
668     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
669
670     rectPrivate->setState("");
671     QCOMPARE(innerRect->x(), qreal(5));
672
673     delete rect;
674 }
675
676 void tst_qdeclarativestates::anchorChanges2()
677 {
678     QDeclarativeEngine engine;
679
680     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges2.qml");
681     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
682     QVERIFY(rect != 0);
683     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
684
685     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
686     QVERIFY(innerRect != 0);
687
688     rectPrivate->setState("right");
689     QCOMPARE(innerRect->x(), qreal(150));
690
691     rectPrivate->setState("");
692     QCOMPARE(innerRect->x(), qreal(5));
693
694     delete rect;
695 }
696
697 void tst_qdeclarativestates::anchorChanges3()
698 {
699     QDeclarativeEngine engine;
700
701     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges3.qml");
702     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
703     QVERIFY(rect != 0);
704     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
705
706     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
707     QVERIFY(innerRect != 0);
708
709     QSGItem *leftGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("LeftGuideline"));
710     QVERIFY(leftGuideline != 0);
711
712     QSGItem *bottomGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("BottomGuideline"));
713     QVERIFY(bottomGuideline != 0);
714
715     QDeclarativeListReference list(rect, "states");
716     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
717     QVERIFY(state != 0);
718
719     qmlExecuteDeferred(state);
720     QSGAnchorChanges *aChanges = qobject_cast<QSGAnchorChanges*>(state->operationAt(0));
721     QVERIFY(aChanges != 0);
722
723     rectPrivate->setState("reanchored");
724     QCOMPARE(aChanges->object(), qobject_cast<QSGItem*>(innerRect));
725     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->left().item, QSGItemPrivate::get(leftGuideline)->left().item);
726     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QSGItemPrivate::get(leftGuideline)->left().anchorLine);
727     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
728     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
729     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->top().item, rectPrivate->top().item);
730     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->top().anchorLine, rectPrivate->top().anchorLine);
731     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->bottom().item, QSGItemPrivate::get(bottomGuideline)->bottom().item);
732     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->bottom().anchorLine, QSGItemPrivate::get(bottomGuideline)->bottom().anchorLine);
733
734     QCOMPARE(innerRect->x(), qreal(10));
735     QCOMPARE(innerRect->y(), qreal(0));
736     QCOMPARE(innerRect->width(), qreal(190));
737     QCOMPARE(innerRect->height(), qreal(150));
738
739     rectPrivate->setState("");
740     QCOMPARE(innerRect->x(), qreal(0));
741     QCOMPARE(innerRect->y(), qreal(10));
742     QCOMPARE(innerRect->width(), qreal(150));
743     QCOMPARE(innerRect->height(), qreal(190));
744
745     delete rect;
746 }
747
748 void tst_qdeclarativestates::anchorChanges4()
749 {
750     QDeclarativeEngine engine;
751
752     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges4.qml");
753     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
754     QVERIFY(rect != 0);
755
756     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
757     QVERIFY(innerRect != 0);
758
759     QSGItem *leftGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("LeftGuideline"));
760     QVERIFY(leftGuideline != 0);
761
762     QSGItem *bottomGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("BottomGuideline"));
763     QVERIFY(bottomGuideline != 0);
764
765     QDeclarativeListReference list(rect, "states");
766     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
767     QVERIFY(state != 0);
768
769     qmlExecuteDeferred(state);
770     QSGAnchorChanges *aChanges = qobject_cast<QSGAnchorChanges*>(state->operationAt(0));
771     QVERIFY(aChanges != 0);
772
773     QSGItemPrivate::get(rect)->setState("reanchored");
774     QCOMPARE(aChanges->object(), qobject_cast<QSGItem*>(innerRect));
775     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().item, QSGItemPrivate::get(bottomGuideline)->horizontalCenter().item);
776     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().anchorLine, QSGItemPrivate::get(bottomGuideline)->horizontalCenter().anchorLine);
777     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->verticalCenter().item, QSGItemPrivate::get(leftGuideline)->verticalCenter().item);
778     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->verticalCenter().anchorLine, QSGItemPrivate::get(leftGuideline)->verticalCenter().anchorLine);
779
780     delete rect;
781 }
782
783 void tst_qdeclarativestates::anchorChanges5()
784 {
785     QDeclarativeEngine engine;
786
787     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges5.qml");
788     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
789     QVERIFY(rect != 0);
790
791     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
792     QVERIFY(innerRect != 0);
793
794     QSGItem *leftGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("LeftGuideline"));
795     QVERIFY(leftGuideline != 0);
796
797     QSGItem *bottomGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("BottomGuideline"));
798     QVERIFY(bottomGuideline != 0);
799
800     QDeclarativeListReference list(rect, "states");
801     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
802     QVERIFY(state != 0);
803
804     qmlExecuteDeferred(state);
805     QSGAnchorChanges *aChanges = qobject_cast<QSGAnchorChanges*>(state->operationAt(0));
806     QVERIFY(aChanges != 0);
807
808     QSGItemPrivate::get(rect)->setState("reanchored");
809     QCOMPARE(aChanges->object(), qobject_cast<QSGItem*>(innerRect));
810     //QCOMPARE(aChanges->anchors()->horizontalCenter().item, bottomGuideline->horizontalCenter().item);
811     //QCOMPARE(aChanges->anchors()->horizontalCenter().anchorLine, bottomGuideline->horizontalCenter().anchorLine);
812     //QCOMPARE(aChanges->anchors()->baseline().item, leftGuideline->baseline().item);
813     //QCOMPARE(aChanges->anchors()->baseline().anchorLine, leftGuideline->baseline().anchorLine);
814
815     delete rect;
816 }
817
818 void mirrorAnchors(QSGItem *item) {
819     QSGItemPrivate *itemPrivate = QSGItemPrivate::get(item);
820     itemPrivate->setLayoutMirror(true);
821 }
822
823 qreal offsetRTL(QSGItem *anchorItem, QSGItem *item) {
824     return anchorItem->width()+2*anchorItem->x()-item->width();
825 }
826
827 void tst_qdeclarativestates::anchorChangesRTL()
828 {
829     QDeclarativeEngine engine;
830
831     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges1.qml");
832     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
833     QVERIFY(rect != 0);
834     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
835
836     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
837     QVERIFY(innerRect != 0);
838     mirrorAnchors(innerRect);
839
840     QDeclarativeListReference list(rect, "states");
841     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
842     QVERIFY(state != 0);
843
844     qmlExecuteDeferred(state);
845     QSGAnchorChanges *aChanges = qobject_cast<QSGAnchorChanges*>(state->operationAt(0));
846     QVERIFY(aChanges != 0);
847
848     rectPrivate->setState("right");
849     QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150));
850     QCOMPARE(aChanges->object(), qobject_cast<QSGItem*>(innerRect));
851     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QSGAnchorLine::Invalid);  //### was reset (how do we distinguish from not set at all)
852     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
853     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
854
855     rectPrivate->setState("");
856     QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) -qreal(5));
857
858     delete rect;
859 }
860
861 void tst_qdeclarativestates::anchorChangesRTL2()
862 {
863     QDeclarativeEngine engine;
864
865     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges2.qml");
866     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
867     QVERIFY(rect != 0);
868     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
869
870     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
871     QVERIFY(innerRect != 0);
872     mirrorAnchors(innerRect);
873
874     rectPrivate->setState("right");
875     QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(150));
876
877     rectPrivate->setState("");
878     QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(5));
879
880     delete rect;
881 }
882
883 void tst_qdeclarativestates::anchorChangesRTL3()
884 {
885     QDeclarativeEngine engine;
886
887     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges3.qml");
888     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
889     QVERIFY(rect != 0);
890     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
891
892     QSGRectangle *innerRect = qobject_cast<QSGRectangle*>(rect->findChild<QSGRectangle*>("MyRect"));
893     QVERIFY(innerRect != 0);
894     mirrorAnchors(innerRect);
895
896     QSGItem *leftGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("LeftGuideline"));
897     QVERIFY(leftGuideline != 0);
898
899     QSGItem *bottomGuideline = qobject_cast<QSGItem*>(rect->findChild<QSGItem*>("BottomGuideline"));
900     QVERIFY(bottomGuideline != 0);
901
902     QDeclarativeListReference list(rect, "states");
903     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
904     QVERIFY(state != 0);
905
906     qmlExecuteDeferred(state);
907     QSGAnchorChanges *aChanges = qobject_cast<QSGAnchorChanges*>(state->operationAt(0));
908     QVERIFY(aChanges != 0);
909
910     rectPrivate->setState("reanchored");
911     QCOMPARE(aChanges->object(), qobject_cast<QSGItem*>(innerRect));
912     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->left().item, QSGItemPrivate::get(leftGuideline)->left().item);
913     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QSGItemPrivate::get(leftGuideline)->left().anchorLine);
914     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item);
915     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine);
916     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->top().item, rectPrivate->top().item);
917     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->top().anchorLine, rectPrivate->top().anchorLine);
918     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->bottom().item, QSGItemPrivate::get(bottomGuideline)->bottom().item);
919     QCOMPARE(QSGItemPrivate::get(aChanges->object())->anchors()->bottom().anchorLine, QSGItemPrivate::get(bottomGuideline)->bottom().anchorLine);
920
921     QCOMPARE(innerRect->x(), offsetRTL(leftGuideline, innerRect) - qreal(10));
922     QCOMPARE(innerRect->y(), qreal(0));
923     // between left side of parent and leftGuideline.x: 10, which has width 0
924     QCOMPARE(innerRect->width(), qreal(10));
925     QCOMPARE(innerRect->height(), qreal(150));
926
927     rectPrivate->setState("");
928     QCOMPARE(innerRect->x(), offsetRTL(rect, innerRect) - qreal(0));
929     QCOMPARE(innerRect->y(), qreal(10));
930     // between right side of parent and left side of rightGuideline.x: 150, which has width 0
931     QCOMPARE(innerRect->width(), qreal(50));
932     QCOMPARE(innerRect->height(), qreal(190));
933
934     delete rect;
935 }
936
937 //QTBUG-9609
938 void tst_qdeclarativestates::anchorChangesCrash()
939 {
940     QDeclarativeEngine engine;
941
942     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChangesCrash.qml");
943     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
944     QVERIFY(rect != 0);
945
946     QSGItemPrivate::get(rect)->setState("reanchored");
947
948     delete rect;
949 }
950
951 // QTBUG-12273
952 void tst_qdeclarativestates::anchorRewindBug()
953 {
954     QSGView *view = new QSGView;
955     view->setSource(QUrl::fromLocalFile(SRCDIR "/data/anchorRewindBug.qml"));
956
957     view->show();
958     view->requestActivateWindow();
959
960     QTest::qWaitForWindowShown(view);
961
962     QSGRectangle *rect = qobject_cast<QSGRectangle*>(view->rootObject());
963     QVERIFY(rect != 0);
964
965     QSGItem * column = rect->findChild<QSGItem*>("column");
966
967     QVERIFY(column != 0);
968     QVERIFY(!QSGItemPrivate::get(column)->heightValid);
969     QVERIFY(!QSGItemPrivate::get(column)->widthValid);
970     QCOMPARE(column->height(), 200.0);
971     QSGItemPrivate::get(rect)->setState("reanchored");
972
973     // column height and width should stay implicit
974     // and column's implicit resizing should still work
975     QVERIFY(!QSGItemPrivate::get(column)->heightValid);
976     QVERIFY(!QSGItemPrivate::get(column)->widthValid);
977     QTRY_COMPARE(column->height(), 100.0);
978
979     QSGItemPrivate::get(rect)->setState("");
980
981     // column height and width should stay implicit
982     // and column's implicit resizing should still work
983     QVERIFY(!QSGItemPrivate::get(column)->heightValid);
984     QVERIFY(!QSGItemPrivate::get(column)->widthValid);
985     QTRY_COMPARE(column->height(), 200.0);
986
987     delete view;
988 }
989
990 // QTBUG-11834
991 void tst_qdeclarativestates::anchorRewindBug2()
992 {
993     QDeclarativeEngine engine;
994
995     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorRewindBug2.qml");
996     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
997     QVERIFY(rect != 0);
998
999     QSGRectangle *mover = rect->findChild<QSGRectangle*>("mover");
1000
1001     QVERIFY(mover != 0);
1002     QCOMPARE(mover->y(), qreal(0.0));
1003     QCOMPARE(mover->width(), qreal(50.0));
1004
1005     QSGItemPrivate::get(rect)->setState("anchored");
1006     QCOMPARE(mover->y(), qreal(250.0));
1007     QCOMPARE(mover->width(), qreal(200.0));
1008
1009     QSGItemPrivate::get(rect)->setState("");
1010     QCOMPARE(mover->y(), qreal(0.0));
1011     QCOMPARE(mover->width(), qreal(50.0));
1012
1013     delete rect;
1014 }
1015
1016 void tst_qdeclarativestates::script()
1017 {
1018     QDeclarativeEngine engine;
1019
1020     {
1021         QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/script.qml");
1022         QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1023         QVERIFY(rect != 0);
1024         QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1025         QCOMPARE(rect->color(),QColor("red"));
1026
1027         rectPrivate->setState("blue");
1028         QCOMPARE(rect->color(),QColor("blue"));
1029
1030         rectPrivate->setState("");
1031         QCOMPARE(rect->color(),QColor("blue")); // a script isn't reverted
1032     }
1033 }
1034
1035 void tst_qdeclarativestates::restoreEntryValues()
1036 {
1037     QDeclarativeEngine engine;
1038
1039     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/restoreEntryValues.qml");
1040     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1041     QVERIFY(rect != 0);
1042     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1043     QCOMPARE(rect->color(),QColor("red"));
1044
1045     rectPrivate->setState("blue");
1046     QCOMPARE(rect->color(),QColor("blue"));
1047
1048     rectPrivate->setState("");
1049     QCOMPARE(rect->color(),QColor("blue"));
1050 }
1051
1052 void tst_qdeclarativestates::explicitChanges()
1053 {
1054     QDeclarativeEngine engine;
1055
1056     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/explicit.qml");
1057     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1058     QVERIFY(rect != 0);
1059     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1060     QDeclarativeListReference list(rect, "states");
1061     QDeclarativeState *state = qobject_cast<QDeclarativeState*>(list.at(0));
1062     QVERIFY(state != 0);
1063
1064     qmlExecuteDeferred(state);
1065     QDeclarativePropertyChanges *changes = qobject_cast<QDeclarativePropertyChanges*>(rect->findChild<QDeclarativePropertyChanges*>("changes"));
1066     QVERIFY(changes != 0);
1067     QVERIFY(changes->isExplicit());
1068
1069     QCOMPARE(rect->color(),QColor("red"));
1070
1071     rectPrivate->setState("blue");
1072     QCOMPARE(rect->color(),QColor("blue"));
1073
1074     rect->setProperty("sourceColor", QColor("green"));
1075     QCOMPARE(rect->color(),QColor("blue"));
1076
1077     rectPrivate->setState("");
1078     QCOMPARE(rect->color(),QColor("red"));
1079     rect->setProperty("sourceColor", QColor("yellow"));
1080     QCOMPARE(rect->color(),QColor("red"));
1081
1082     rectPrivate->setState("blue");
1083     QCOMPARE(rect->color(),QColor("yellow"));
1084 }
1085
1086 void tst_qdeclarativestates::propertyErrors()
1087 {
1088     QDeclarativeEngine engine;
1089     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/propertyErrors.qml");
1090     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1091     QVERIFY(rect != 0);
1092
1093     QCOMPARE(rect->color(),QColor("red"));
1094
1095     QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/propertyErrors.qml") + ":8:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\"");
1096     QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/propertyErrors.qml") + ":8:9: QML PropertyChanges: Cannot assign to read-only property \"activeFocus\"");
1097     QSGItemPrivate::get(rect)->setState("blue");
1098 }
1099
1100 void tst_qdeclarativestates::incorrectRestoreBug()
1101 {
1102     QDeclarativeEngine engine;
1103
1104     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges.qml");
1105     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1106     QVERIFY(rect != 0);
1107     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1108     QCOMPARE(rect->color(),QColor("red"));
1109
1110     rectPrivate->setState("blue");
1111     QCOMPARE(rect->color(),QColor("blue"));
1112
1113     rectPrivate->setState("");
1114     QCOMPARE(rect->color(),QColor("red"));
1115
1116     // make sure if we change the base state value, we then restore to it correctly
1117     rect->setColor(QColor("green"));
1118
1119     rectPrivate->setState("blue");
1120     QCOMPARE(rect->color(),QColor("blue"));
1121
1122     rectPrivate->setState("");
1123     QCOMPARE(rect->color(),QColor("green"));
1124 }
1125
1126 void tst_qdeclarativestates::autoStateAtStartupRestoreBug()
1127 {
1128     QDeclarativeEngine engine;
1129
1130     QDeclarativeComponent component(&engine, SRCDIR "/data/autoStateAtStartupRestoreBug.qml");
1131     QObject *obj = component.create();
1132
1133     QVERIFY(obj != 0);
1134     QCOMPARE(obj->property("test").toInt(), 3);
1135
1136     obj->setProperty("input", 2);
1137
1138     QCOMPARE(obj->property("test").toInt(), 9);
1139
1140     delete obj;
1141 }
1142
1143 void tst_qdeclarativestates::deletingChange()
1144 {
1145     QDeclarativeEngine engine;
1146
1147     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/deleting.qml");
1148     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1149     QVERIFY(rect != 0);
1150     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1151     rectPrivate->setState("blue");
1152     QCOMPARE(rect->color(),QColor("blue"));
1153     QCOMPARE(rect->radius(),qreal(5));
1154
1155     rectPrivate->setState("");
1156     QCOMPARE(rect->color(),QColor("red"));
1157     QCOMPARE(rect->radius(),qreal(0));
1158
1159     QDeclarativePropertyChanges *pc = rect->findChild<QDeclarativePropertyChanges*>("pc1");
1160     QVERIFY(pc != 0);
1161     delete pc;
1162
1163     QDeclarativeState *state = rect->findChild<QDeclarativeState*>();
1164     QVERIFY(state != 0);
1165     qmlExecuteDeferred(state);
1166     QCOMPARE(state->operationCount(), 1);
1167
1168     rectPrivate->setState("blue");
1169     QCOMPARE(rect->color(),QColor("red"));
1170     QCOMPARE(rect->radius(),qreal(5));
1171
1172     delete rect;
1173 }
1174
1175 void tst_qdeclarativestates::deletingState()
1176 {
1177     QDeclarativeEngine engine;
1178
1179     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/deletingState.qml");
1180     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1181     QVERIFY(rect != 0);
1182
1183     QDeclarativeStateGroup *sg = rect->findChild<QDeclarativeStateGroup*>();
1184     QVERIFY(sg != 0);
1185     QVERIFY(sg->findState("blue") != 0);
1186
1187     sg->setState("blue");
1188     QCOMPARE(rect->color(),QColor("blue"));
1189
1190     sg->setState("");
1191     QCOMPARE(rect->color(),QColor("red"));
1192
1193     QDeclarativeState *state = rect->findChild<QDeclarativeState*>();
1194     QVERIFY(state != 0);
1195     delete state;
1196
1197     QVERIFY(sg->findState("blue") == 0);
1198
1199     //### should we warn that state doesn't exist
1200     sg->setState("blue");
1201     QCOMPARE(rect->color(),QColor("red"));
1202
1203     delete rect;
1204 }
1205
1206 void tst_qdeclarativestates::tempState()
1207 {
1208     QDeclarativeEngine engine;
1209
1210     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/legalTempState.qml");
1211     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1212     QVERIFY(rect != 0);
1213     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1214     QTest::ignoreMessage(QtDebugMsg, "entering placed");
1215     QTest::ignoreMessage(QtDebugMsg, "entering idle");
1216     rectPrivate->setState("placed");
1217     QCOMPARE(rectPrivate->state(), QLatin1String("idle"));
1218 }
1219
1220 void tst_qdeclarativestates::illegalTempState()
1221 {
1222     QDeclarativeEngine engine;
1223
1224     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/illegalTempState.qml");
1225     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1226     QVERIFY(rect != 0);
1227     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1228     QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: QML StateGroup: Can't apply a state change as part of a state definition.");
1229     rectPrivate->setState("placed");
1230     QCOMPARE(rectPrivate->state(), QLatin1String("placed"));
1231 }
1232
1233 void tst_qdeclarativestates::nonExistantProperty()
1234 {
1235     QDeclarativeEngine engine;
1236
1237     QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/nonExistantProp.qml");
1238     QSGRectangle *rect = qobject_cast<QSGRectangle*>(rectComponent.create());
1239     QVERIFY(rect != 0);
1240     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1241     QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/nonExistantProp.qml") + ":9:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\"");
1242     rectPrivate->setState("blue");
1243     QCOMPARE(rectPrivate->state(), QLatin1String("blue"));
1244 }
1245
1246 void tst_qdeclarativestates::reset()
1247 {
1248     QDeclarativeEngine engine;
1249
1250     QDeclarativeComponent c(&engine, SRCDIR "/data/reset.qml");
1251     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1252     QVERIFY(rect != 0);
1253
1254     QSGImage *image = rect->findChild<QSGImage*>();
1255     QVERIFY(image != 0);
1256     QCOMPARE(image->width(), qreal(40.));
1257     QCOMPARE(image->height(), qreal(20.));
1258
1259     QSGItemPrivate::get(rect)->setState("state1");
1260
1261     QCOMPARE(image->width(), 20.0);
1262     QCOMPARE(image->height(), qreal(20.));
1263 }
1264
1265 void tst_qdeclarativestates::illegalObjectCreation()
1266 {
1267     QDeclarativeEngine engine;
1268
1269     QDeclarativeComponent component(&engine, SRCDIR "/data/illegalObj.qml");
1270     QList<QDeclarativeError> errors = component.errors();
1271     QVERIFY(errors.count() == 1);
1272     const QDeclarativeError &error = errors.at(0);
1273     QCOMPARE(error.line(), 9);
1274     QCOMPARE(error.column(), 23);
1275     QCOMPARE(error.description().toUtf8().constData(), "PropertyChanges does not support creating state-specific objects.");
1276 }
1277
1278 void tst_qdeclarativestates::whenOrdering()
1279 {
1280     QDeclarativeEngine engine;
1281
1282     QDeclarativeComponent c(&engine, SRCDIR "/data/whenOrdering.qml");
1283     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1284     QVERIFY(rect != 0);
1285     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1286
1287     QCOMPARE(rectPrivate->state(), QLatin1String(""));
1288     rect->setProperty("condition2", true);
1289     QCOMPARE(rectPrivate->state(), QLatin1String("state2"));
1290     rect->setProperty("condition1", true);
1291     QCOMPARE(rectPrivate->state(), QLatin1String("state1"));
1292     rect->setProperty("condition2", false);
1293     QCOMPARE(rectPrivate->state(), QLatin1String("state1"));
1294     rect->setProperty("condition2", true);
1295     QCOMPARE(rectPrivate->state(), QLatin1String("state1"));
1296     rect->setProperty("condition1", false);
1297     rect->setProperty("condition2", false);
1298     QCOMPARE(rectPrivate->state(), QLatin1String(""));
1299 }
1300
1301 void tst_qdeclarativestates::urlResolution()
1302 {
1303     QDeclarativeEngine engine;
1304
1305     QDeclarativeComponent c(&engine, SRCDIR "/data/urlResolution.qml");
1306     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1307     QVERIFY(rect != 0);
1308
1309     QSGItem *myType = rect->findChild<QSGItem*>("MyType");
1310     QSGImage *image1 = rect->findChild<QSGImage*>("image1");
1311     QSGImage *image2 = rect->findChild<QSGImage*>("image2");
1312     QSGImage *image3 = rect->findChild<QSGImage*>("image3");
1313     QVERIFY(myType != 0 && image1 != 0 && image2 != 0 && image3 != 0);
1314
1315     QSGItemPrivate::get(myType)->setState("SetImageState");
1316     QUrl resolved = QUrl::fromLocalFile(SRCDIR "/data/Implementation/images/qt-logo.png");
1317     QCOMPARE(image1->source(), resolved);
1318     QCOMPARE(image2->source(), resolved);
1319     QCOMPARE(image3->source(), resolved);
1320 }
1321
1322 void tst_qdeclarativestates::unnamedWhen()
1323 {
1324     QDeclarativeEngine engine;
1325
1326     QDeclarativeComponent c(&engine, SRCDIR "/data/unnamedWhen.qml");
1327     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1328     QVERIFY(rect != 0);
1329     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1330
1331     QCOMPARE(rectPrivate->state(), QLatin1String(""));
1332     QCOMPARE(rect->property("stateString").toString(), QLatin1String(""));
1333     rect->setProperty("triggerState", true);
1334     QCOMPARE(rectPrivate->state(), QLatin1String("anonymousState1"));
1335     QCOMPARE(rect->property("stateString").toString(), QLatin1String("inState"));
1336     rect->setProperty("triggerState", false);
1337     QCOMPARE(rectPrivate->state(), QLatin1String(""));
1338     QCOMPARE(rect->property("stateString").toString(), QLatin1String(""));
1339 }
1340
1341 void tst_qdeclarativestates::returnToBase()
1342 {
1343     QDeclarativeEngine engine;
1344
1345     QDeclarativeComponent c(&engine, SRCDIR "/data/returnToBase.qml");
1346     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1347     QVERIFY(rect != 0);
1348     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1349
1350     QCOMPARE(rectPrivate->state(), QLatin1String(""));
1351     QCOMPARE(rect->property("stateString").toString(), QLatin1String(""));
1352     rect->setProperty("triggerState", true);
1353     QCOMPARE(rectPrivate->state(), QLatin1String("anonymousState1"));
1354     QCOMPARE(rect->property("stateString").toString(), QLatin1String("inState"));
1355     rect->setProperty("triggerState", false);
1356     QCOMPARE(rectPrivate->state(), QLatin1String(""));
1357     QCOMPARE(rect->property("stateString").toString(), QLatin1String("originalState"));
1358 }
1359
1360 //QTBUG-12559
1361 void tst_qdeclarativestates::extendsBug()
1362 {
1363     QDeclarativeEngine engine;
1364
1365     QDeclarativeComponent c(&engine, SRCDIR "/data/extendsBug.qml");
1366     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1367     QVERIFY(rect != 0);
1368     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1369     QSGRectangle *greenRect = rect->findChild<QSGRectangle*>("greenRect");
1370
1371     rectPrivate->setState("b");
1372     QCOMPARE(greenRect->x(), qreal(100));
1373     QCOMPARE(greenRect->y(), qreal(100));
1374 }
1375
1376 void tst_qdeclarativestates::editProperties()
1377 {
1378     QDeclarativeEngine engine;
1379
1380     QDeclarativeComponent c(&engine, SRCDIR "/data/editProperties.qml");
1381     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1382     QVERIFY(rect != 0);
1383
1384     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1385
1386     QDeclarativeStateGroup *stateGroup = rectPrivate->_states();
1387     QVERIFY(stateGroup != 0);
1388     qmlExecuteDeferred(stateGroup);
1389
1390     QDeclarativeState *blueState = stateGroup->findState("blue");
1391     QVERIFY(blueState != 0);
1392     qmlExecuteDeferred(blueState);
1393
1394     QDeclarativePropertyChanges *propertyChangesBlue = qobject_cast<QDeclarativePropertyChanges*>(blueState->operationAt(0));
1395     QVERIFY(propertyChangesBlue != 0);
1396
1397     QDeclarativeState *greenState = stateGroup->findState("green");
1398     QVERIFY(greenState != 0);
1399     qmlExecuteDeferred(greenState);
1400
1401     QDeclarativePropertyChanges *propertyChangesGreen = qobject_cast<QDeclarativePropertyChanges*>(greenState->operationAt(0));
1402     QVERIFY(propertyChangesGreen != 0);
1403
1404     QSGRectangle *childRect = rect->findChild<QSGRectangle*>("rect2");
1405     QVERIFY(childRect != 0);
1406     QCOMPARE(childRect->width(), qreal(402));
1407     QVERIFY(QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1408     QCOMPARE(childRect->height(), qreal(200));
1409
1410     rectPrivate->setState("blue");
1411     QCOMPARE(childRect->width(), qreal(50));
1412     QCOMPARE(childRect->height(), qreal(40));
1413     QVERIFY(!QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1414     QVERIFY(blueState->bindingInRevertList(childRect, "width"));
1415
1416
1417     rectPrivate->setState("green");
1418     QCOMPARE(childRect->width(), qreal(200));
1419     QCOMPARE(childRect->height(), qreal(100));
1420     QVERIFY(greenState->bindingInRevertList(childRect, "width"));
1421
1422
1423     rectPrivate->setState("");
1424
1425
1426     QCOMPARE(propertyChangesBlue->actions().length(), 2);
1427     QVERIFY(propertyChangesBlue->containsValue("width"));
1428     QVERIFY(!propertyChangesBlue->containsProperty("x"));
1429     QCOMPARE(propertyChangesBlue->value("width").toInt(), 50);
1430     QVERIFY(!propertyChangesBlue->value("x").isValid());
1431
1432     propertyChangesBlue->changeValue("width", 60);
1433     QCOMPARE(propertyChangesBlue->value("width").toInt(), 60);
1434     QCOMPARE(propertyChangesBlue->actions().length(), 2);
1435
1436
1437     propertyChangesBlue->changeExpression("width", "myRectangle.width / 2");
1438     QVERIFY(!propertyChangesBlue->containsValue("width"));
1439     QVERIFY(propertyChangesBlue->containsExpression("width"));
1440     QCOMPARE(propertyChangesBlue->value("width").toInt(), 0);
1441     QCOMPARE(propertyChangesBlue->actions().length(), 2);
1442
1443     propertyChangesBlue->changeValue("width", 50);
1444     QVERIFY(propertyChangesBlue->containsValue("width"));
1445     QVERIFY(!propertyChangesBlue->containsExpression("width"));
1446     QCOMPARE(propertyChangesBlue->value("width").toInt(), 50);
1447     QCOMPARE(propertyChangesBlue->actions().length(), 2);
1448
1449     QVERIFY(QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1450     rectPrivate->setState("blue");
1451     QCOMPARE(childRect->width(), qreal(50));
1452     QCOMPARE(childRect->height(), qreal(40));
1453
1454     propertyChangesBlue->changeValue("width", 60);
1455     QCOMPARE(propertyChangesBlue->value("width").toInt(), 60);
1456     QCOMPARE(propertyChangesBlue->actions().length(), 2);
1457     QCOMPARE(childRect->width(), qreal(60));
1458     QVERIFY(!QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1459
1460     propertyChangesBlue->changeExpression("width", "myRectangle.width / 2");
1461     QVERIFY(!propertyChangesBlue->containsValue("width"));
1462     QVERIFY(propertyChangesBlue->containsExpression("width"));
1463     QCOMPARE(propertyChangesBlue->value("width").toInt(), 0);
1464     QCOMPARE(propertyChangesBlue->actions().length(), 2);
1465     QVERIFY(QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1466     QCOMPARE(childRect->width(), qreal(200));
1467
1468     propertyChangesBlue->changeValue("width", 50);
1469     QCOMPARE(childRect->width(), qreal(50));
1470
1471     rectPrivate->setState("");
1472     QCOMPARE(childRect->width(), qreal(402));
1473     QVERIFY(QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1474
1475     QCOMPARE(propertyChangesGreen->actions().length(), 2);
1476     rectPrivate->setState("green");
1477     QCOMPARE(childRect->width(), qreal(200));
1478     QCOMPARE(childRect->height(), qreal(100));
1479     QVERIFY(QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1480     QVERIFY(greenState->bindingInRevertList(childRect, "width"));
1481     QCOMPARE(propertyChangesGreen->actions().length(), 2);
1482
1483
1484     propertyChangesGreen->removeProperty("height");
1485     QVERIFY(!QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "height")));
1486     QCOMPARE(childRect->height(), qreal(200));
1487
1488     QVERIFY(greenState->bindingInRevertList(childRect, "width"));
1489     QVERIFY(greenState->containsPropertyInRevertList(childRect, "width"));
1490     propertyChangesGreen->removeProperty("width");
1491     QVERIFY(QDeclarativePropertyPrivate::binding(QDeclarativeProperty(childRect, "width")));
1492     QCOMPARE(childRect->width(), qreal(402));
1493     QVERIFY(!greenState->bindingInRevertList(childRect, "width"));
1494     QVERIFY(!greenState->containsPropertyInRevertList(childRect, "width"));
1495
1496     propertyChangesBlue->removeProperty("width");
1497     QCOMPARE(childRect->width(), qreal(402));
1498
1499     rectPrivate->setState("blue");
1500     QCOMPARE(childRect->width(), qreal(402));
1501     QCOMPARE(childRect->height(), qreal(40));
1502 }
1503
1504 void tst_qdeclarativestates::QTBUG_14830()
1505 {
1506     QDeclarativeEngine engine;
1507
1508     QDeclarativeComponent c(&engine, SRCDIR "/data/QTBUG-14830.qml");
1509     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1510     QVERIFY(rect != 0);
1511     QSGItem *item = rect->findChild<QSGItem*>("area");
1512
1513     QCOMPARE(item->width(), qreal(171));
1514 }
1515
1516 void tst_qdeclarativestates::avoidFastForward()
1517 {
1518     QDeclarativeEngine engine;
1519
1520     //shouldn't fast forward if there isn't a transition
1521     QDeclarativeComponent c(&engine, SRCDIR "/data/avoidFastForward.qml");
1522     QSGRectangle *rect = qobject_cast<QSGRectangle*>(c.create());
1523     QVERIFY(rect != 0);
1524
1525     QSGItemPrivate *rectPrivate = QSGItemPrivate::get(rect);
1526     rectPrivate->setState("a");
1527     QCOMPARE(rect->property("updateCount").toInt(), 1);
1528 }
1529
1530 QTEST_MAIN(tst_qdeclarativestates)
1531
1532 #include "tst_qdeclarativestates.moc"