diff -r b72c6db6890b -r 5dc02b23752f tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/auto/declarative/qdeclarativestates/tst_qdeclarativestates.cpp Tue Jul 06 15:10:48 2010 +0300 @@ -0,0 +1,1090 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +class MyRect : public QDeclarativeRectangle +{ + Q_OBJECT + Q_PROPERTY(int propertyWithNotify READ propertyWithNotify WRITE setPropertyWithNotify NOTIFY oddlyNamedNotifySignal) +public: + MyRect() {} + + void doSomething() { emit didSomething(); } + + int propertyWithNotify() const { return m_prop; } + void setPropertyWithNotify(int i) { m_prop = i; emit oddlyNamedNotifySignal(); } +Q_SIGNALS: + void didSomething(); + void oddlyNamedNotifySignal(); + +private: + int m_prop; +}; + + +class tst_qdeclarativestates : public QObject +{ + Q_OBJECT +public: + tst_qdeclarativestates() {} + +private: + static QByteArray fullDataPath(const QString &path); + +private slots: + void initTestCase(); + + void basicChanges(); + void basicExtension(); + void basicBinding(); + void signalOverride(); + void signalOverrideCrash(); + void signalOverrideCrash2(); + void parentChange(); + void parentChangeErrors(); + void anchorChanges(); + void anchorChanges2(); + void anchorChanges3(); + void anchorChanges4(); + void anchorChanges5(); + void anchorChangesCrash(); + void script(); + void restoreEntryValues(); + void explicitChanges(); + void propertyErrors(); + void incorrectRestoreBug(); + void autoStateAtStartupRestoreBug(); + void deletingChange(); + void deletingState(); + void tempState(); + void illegalTempState(); + void nonExistantProperty(); + void reset(); + void illegalObjectCreation(); + void whenOrdering(); + void urlResolution(); + void unnamedWhen(); +}; + +void tst_qdeclarativestates::initTestCase() +{ + qmlRegisterType("Qt.test", 1, 0, "MyRectangle"); +} + +QByteArray tst_qdeclarativestates::fullDataPath(const QString &path) +{ + return QUrl::fromLocalFile(SRCDIR + path).toString().toUtf8(); +} + +void tst_qdeclarativestates::basicChanges() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges2.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges3.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),1); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->border()->width(),1); + + rectPrivate->setState("bordered"); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),2); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),1); + //### we should be checking that this is an implicit rather than explicit 1 (which currently fails) + + rectPrivate->setState("bordered"); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),2); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->border()->width(),1); + + } + + { + // Test basicChanges4.qml can magically connect to propertyWithNotify's notify + // signal using 'onPropertyWithNotifyChanged' even though the signal name is + // actually 'oddlyNamedNotifySignal' + + QDeclarativeComponent component(&engine, SRCDIR "/data/basicChanges4.qml"); + QVERIFY(component.isReady()); + + MyRect *rect = qobject_cast(component.create()); + QVERIFY(rect != 0); + + QMetaProperty prop = rect->metaObject()->property(rect->metaObject()->indexOfProperty("propertyWithNotify")); + QVERIFY(prop.hasNotifySignal()); + QString notifySignal = QByteArray(prop.notifySignal().signature()); + QVERIFY(!notifySignal.startsWith("propertyWithNotifyChanged(")); + + QCOMPARE(rect->color(), QColor(Qt::red)); + + rect->setPropertyWithNotify(100); + QCOMPARE(rect->color(), QColor(Qt::blue)); + } +} + +void tst_qdeclarativestates::basicExtension() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicExtension.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),1); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->border()->width(),1); + + rectPrivate->setState("bordered"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->border()->width(),2); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->border()->width(),1); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),1); + + rectPrivate->setState("bordered"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->border()->width(),2); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->border()->width(),1); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/fakeExtension.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + } +} + +void tst_qdeclarativestates::basicBinding() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + rect->setProperty("sourceColor", QColor("green")); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + rect->setProperty("sourceColor", QColor("yellow")); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("yellow")); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding2.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + rect->setProperty("sourceColor", QColor("green")); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("green")); + rect->setProperty("sourceColor", QColor("yellow")); + QCOMPARE(rect->color(),QColor("yellow")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("yellow")); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding3.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + rect->setProperty("sourceColor", QColor("green")); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + rect->setProperty("sourceColor", QColor("red")); + QCOMPARE(rect->color(),QColor("blue")); + rect->setProperty("sourceColor2", QColor("yellow")); + QCOMPARE(rect->color(),QColor("yellow")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + rect->setProperty("sourceColor2", QColor("green")); + QCOMPARE(rect->color(),QColor("red")); + rect->setProperty("sourceColor", QColor("yellow")); + QCOMPARE(rect->color(),QColor("yellow")); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicBinding4.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + rect->setProperty("sourceColor", QColor("yellow")); + QCOMPARE(rect->color(),QColor("yellow")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + rect->setProperty("sourceColor", QColor("purple")); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("purple")); + + rectPrivate->setState("green"); + QCOMPARE(rect->color(),QColor("green")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + } +} + +void tst_qdeclarativestates::signalOverride() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverride.qml"); + MyRect *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + rect->doSomething(); + QCOMPARE(rect->color(),QColor("blue")); + + QDeclarativeItemPrivate::get(rect)->setState("green"); + rect->doSomething(); + QCOMPARE(rect->color(),QColor("green")); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverride2.qml"); + MyRect *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("white")); + rect->doSomething(); + QCOMPARE(rect->color(),QColor("blue")); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("extendedRect")); + QDeclarativeItemPrivate::get(innerRect)->setState("green"); + rect->doSomething(); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(innerRect->color(),QColor("green")); + QCOMPARE(innerRect->property("extendedColor").value(),QColor("green")); + } +} + +void tst_qdeclarativestates::signalOverrideCrash() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverrideCrash.qml"); + MyRect *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeItemPrivate::get(rect)->setState("overridden"); + rect->doSomething(); +} + +void tst_qdeclarativestates::signalOverrideCrash2() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/signalOverrideCrash2.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeItemPrivate::get(rect)->setState("state1"); + QDeclarativeItemPrivate::get(rect)->setState("state2"); + QDeclarativeItemPrivate::get(rect)->setState("state1"); + + delete rect; +} + +void tst_qdeclarativestates::parentChange() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange1.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeParentChange *pChange = qobject_cast(state->operationAt(0)); + QVERIFY(pChange != 0); + QDeclarativeItem *nParent = qobject_cast(rect->findChild("NewParent")); + QVERIFY(nParent != 0); + + QCOMPARE(pChange->parent(), nParent); + + QDeclarativeItemPrivate::get(rect)->setState("reparented"); + QCOMPARE(innerRect->rotation(), qreal(0)); + QCOMPARE(innerRect->scale(), qreal(1)); + QCOMPARE(innerRect->x(), qreal(-133)); + QCOMPARE(innerRect->y(), qreal(-300)); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange2.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + rectPrivate->setState("reparented"); + QCOMPARE(innerRect->rotation(), qreal(15)); + QCOMPARE(innerRect->scale(), qreal(.5)); + QCOMPARE(QString("%1").arg(innerRect->x()), QString("%1").arg(-19.9075)); + QCOMPARE(QString("%1").arg(innerRect->y()), QString("%1").arg(-8.73433)); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange3.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + rectPrivate->setState("reparented"); + QCOMPARE(innerRect->rotation(), qreal(-37)); + QCOMPARE(innerRect->scale(), qreal(.25)); + QCOMPARE(QString("%1").arg(innerRect->x()), QString("%1").arg(-217.305)); + QCOMPARE(QString("%1").arg(innerRect->y()), QString("%1").arg(-164.413)); + + rectPrivate->setState(""); + QCOMPARE(innerRect->rotation(), qreal(0)); + QCOMPARE(innerRect->scale(), qreal(1)); + QCOMPARE(innerRect->x(), qreal(5)); + //do a non-qFuzzyCompare fuzzy compare + QVERIFY(innerRect->y() < qreal(0.00001) && innerRect->y() > qreal(-0.00001)); + } +} + +void tst_qdeclarativestates::parentChangeErrors() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange4.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/parentChange4.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under non-uniform scale"); + QDeclarativeItemPrivate::get(rect)->setState("reparented"); + QCOMPARE(innerRect->rotation(), qreal(0)); + QCOMPARE(innerRect->scale(), qreal(1)); + QCOMPARE(innerRect->x(), qreal(5)); + QCOMPARE(innerRect->y(), qreal(5)); + } + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/parentChange5.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/parentChange5.qml") + ":25:9: QML ParentChange: Unable to preserve appearance under complex transform"); + QDeclarativeItemPrivate::get(rect)->setState("reparented"); + QCOMPARE(innerRect->rotation(), qreal(0)); + QCOMPARE(innerRect->scale(), qreal(1)); + QCOMPARE(innerRect->x(), qreal(5)); + QCOMPARE(innerRect->y(), qreal(5)); + } +} + +void tst_qdeclarativestates::anchorChanges() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges1.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeAnchorChanges *aChanges = qobject_cast(state->operationAt(0)); + QVERIFY(aChanges != 0); + + rectPrivate->setState("right"); + QCOMPARE(innerRect->x(), qreal(150)); + QCOMPARE(aChanges->object(), qobject_cast(innerRect)); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QDeclarativeAnchorLine::Invalid); //### was reset (how do we distinguish from not set at all) + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine); + + rectPrivate->setState(""); + QCOMPARE(innerRect->x(), qreal(5)); + + delete rect; +} + +void tst_qdeclarativestates::anchorChanges2() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges2.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + rectPrivate->setState("right"); + QCOMPARE(innerRect->x(), qreal(150)); + + rectPrivate->setState(""); + QCOMPARE(innerRect->x(), qreal(5)); + + delete rect; +} + +void tst_qdeclarativestates::anchorChanges3() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges3.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QDeclarativeItem *leftGuideline = qobject_cast(rect->findChild("LeftGuideline")); + QVERIFY(leftGuideline != 0); + + QDeclarativeItem *bottomGuideline = qobject_cast(rect->findChild("BottomGuideline")); + QVERIFY(bottomGuideline != 0); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeAnchorChanges *aChanges = qobject_cast(state->operationAt(0)); + QVERIFY(aChanges != 0); + + rectPrivate->setState("reanchored"); + QCOMPARE(aChanges->object(), qobject_cast(innerRect)); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->left().item, QDeclarativeItemPrivate::get(leftGuideline)->left().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->left().anchorLine, QDeclarativeItemPrivate::get(leftGuideline)->left().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().item, rectPrivate->right().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->right().anchorLine, rectPrivate->right().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->top().item, rectPrivate->top().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->top().anchorLine, rectPrivate->top().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->bottom().item, QDeclarativeItemPrivate::get(bottomGuideline)->bottom().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->bottom().anchorLine, QDeclarativeItemPrivate::get(bottomGuideline)->bottom().anchorLine); + + QCOMPARE(innerRect->x(), qreal(10)); + QCOMPARE(innerRect->y(), qreal(0)); + QCOMPARE(innerRect->width(), qreal(190)); + QCOMPARE(innerRect->height(), qreal(150)); + + rectPrivate->setState(""); + QCOMPARE(innerRect->x(), qreal(0)); + QCOMPARE(innerRect->y(), qreal(10)); + QCOMPARE(innerRect->width(), qreal(150)); + QCOMPARE(innerRect->height(), qreal(190)); + + delete rect; +} + +void tst_qdeclarativestates::anchorChanges4() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges4.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QDeclarativeItem *leftGuideline = qobject_cast(rect->findChild("LeftGuideline")); + QVERIFY(leftGuideline != 0); + + QDeclarativeItem *bottomGuideline = qobject_cast(rect->findChild("BottomGuideline")); + QVERIFY(bottomGuideline != 0); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeAnchorChanges *aChanges = qobject_cast(state->operationAt(0)); + QVERIFY(aChanges != 0); + + QDeclarativeItemPrivate::get(rect)->setState("reanchored"); + QCOMPARE(aChanges->object(), qobject_cast(innerRect)); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().item, QDeclarativeItemPrivate::get(bottomGuideline)->horizontalCenter().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->horizontalCenter().anchorLine, QDeclarativeItemPrivate::get(bottomGuideline)->horizontalCenter().anchorLine); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->verticalCenter().item, QDeclarativeItemPrivate::get(leftGuideline)->verticalCenter().item); + QCOMPARE(QDeclarativeItemPrivate::get(aChanges->object())->anchors()->verticalCenter().anchorLine, QDeclarativeItemPrivate::get(leftGuideline)->verticalCenter().anchorLine); + + delete rect; +} + +void tst_qdeclarativestates::anchorChanges5() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChanges5.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeRectangle *innerRect = qobject_cast(rect->findChild("MyRect")); + QVERIFY(innerRect != 0); + + QDeclarativeItem *leftGuideline = qobject_cast(rect->findChild("LeftGuideline")); + QVERIFY(leftGuideline != 0); + + QDeclarativeItem *bottomGuideline = qobject_cast(rect->findChild("BottomGuideline")); + QVERIFY(bottomGuideline != 0); + + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativeAnchorChanges *aChanges = qobject_cast(state->operationAt(0)); + QVERIFY(aChanges != 0); + + QDeclarativeItemPrivate::get(rect)->setState("reanchored"); + QCOMPARE(aChanges->object(), qobject_cast(innerRect)); + //QCOMPARE(aChanges->anchors()->horizontalCenter().item, bottomGuideline->horizontalCenter().item); + //QCOMPARE(aChanges->anchors()->horizontalCenter().anchorLine, bottomGuideline->horizontalCenter().anchorLine); + //QCOMPARE(aChanges->anchors()->baseline().item, leftGuideline->baseline().item); + //QCOMPARE(aChanges->anchors()->baseline().anchorLine, leftGuideline->baseline().anchorLine); + + delete rect; +} + +//QTBUG-9609 +void tst_qdeclarativestates::anchorChangesCrash() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/anchorChangesCrash.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeItemPrivate::get(rect)->setState("reanchored"); + + delete rect; +} + +void tst_qdeclarativestates::script() +{ + QDeclarativeEngine engine; + + { + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/script.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("blue")); // a script isn't reverted + } +} + +void tst_qdeclarativestates::restoreEntryValues() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/restoreEntryValues.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("blue")); +} + +void tst_qdeclarativestates::explicitChanges() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/explicit.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QDeclarativeListReference list(rect, "states"); + QDeclarativeState *state = qobject_cast(list.at(0)); + QVERIFY(state != 0); + + qmlExecuteDeferred(state); + QDeclarativePropertyChanges *changes = qobject_cast(rect->findChild("changes")); + QVERIFY(changes != 0); + QVERIFY(changes->isExplicit()); + + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rect->setProperty("sourceColor", QColor("green")); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + rect->setProperty("sourceColor", QColor("yellow")); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("yellow")); +} + +void tst_qdeclarativestates::propertyErrors() +{ + QDeclarativeEngine engine; + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/propertyErrors.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QCOMPARE(rect->color(),QColor("red")); + + QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/propertyErrors.qml") + ":8:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\""); + QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/propertyErrors.qml") + ":8:9: QML PropertyChanges: Cannot assign to read-only property \"wantsFocus\""); + QDeclarativeItemPrivate::get(rect)->setState("blue"); +} + +void tst_qdeclarativestates::incorrectRestoreBug() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/basicChanges.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QCOMPARE(rect->color(),QColor("red")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + + // make sure if we change the base state value, we then restore to it correctly + rect->setColor(QColor("green")); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("green")); +} + +void tst_qdeclarativestates::autoStateAtStartupRestoreBug() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent component(&engine, SRCDIR "/data/autoStateAtStartupRestoreBug.qml"); + QObject *obj = component.create(); + + QVERIFY(obj != 0); + QCOMPARE(obj->property("test").toInt(), 3); + + obj->setProperty("input", 2); + + QCOMPARE(obj->property("test").toInt(), 9); + + delete obj; +} + +void tst_qdeclarativestates::deletingChange() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/deleting.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + QCOMPARE(rect->radius(),qreal(5)); + + rectPrivate->setState(""); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->radius(),qreal(0)); + + QDeclarativePropertyChanges *pc = rect->findChild("pc1"); + QVERIFY(pc != 0); + delete pc; + + QDeclarativeState *state = rect->findChild(); + QVERIFY(state != 0); + qmlExecuteDeferred(state); + QCOMPARE(state->operationCount(), 1); + + rectPrivate->setState("blue"); + QCOMPARE(rect->color(),QColor("red")); + QCOMPARE(rect->radius(),qreal(5)); + + delete rect; +} + +void tst_qdeclarativestates::deletingState() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/deletingState.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + + QDeclarativeStateGroup *sg = rect->findChild(); + QVERIFY(sg != 0); + QVERIFY(sg->findState("blue") != 0); + + sg->setState("blue"); + QCOMPARE(rect->color(),QColor("blue")); + + sg->setState(""); + QCOMPARE(rect->color(),QColor("red")); + + QDeclarativeState *state = rect->findChild(); + QVERIFY(state != 0); + delete state; + + QVERIFY(sg->findState("blue") == 0); + + //### should we warn that state doesn't exist + sg->setState("blue"); + QCOMPARE(rect->color(),QColor("red")); + + delete rect; +} + +void tst_qdeclarativestates::tempState() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/legalTempState.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QTest::ignoreMessage(QtDebugMsg, "entering placed"); + QTest::ignoreMessage(QtDebugMsg, "entering idle"); + rectPrivate->setState("placed"); + QCOMPARE(rectPrivate->state(), QLatin1String("idle")); +} + +void tst_qdeclarativestates::illegalTempState() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/illegalTempState.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QTest::ignoreMessage(QtWarningMsg, ": QML StateGroup: Can't apply a state change as part of a state definition."); + rectPrivate->setState("placed"); + QCOMPARE(rectPrivate->state(), QLatin1String("placed")); +} + +void tst_qdeclarativestates::nonExistantProperty() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent rectComponent(&engine, SRCDIR "/data/nonExistantProp.qml"); + QDeclarativeRectangle *rect = qobject_cast(rectComponent.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + QTest::ignoreMessage(QtWarningMsg, fullDataPath("/data/nonExistantProp.qml") + ":9:9: QML PropertyChanges: Cannot assign to non-existent property \"colr\""); + rectPrivate->setState("blue"); + QCOMPARE(rectPrivate->state(), QLatin1String("blue")); +} + +void tst_qdeclarativestates::reset() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/reset.qml"); + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + + QDeclarativeText *text = rect->findChild(); + QVERIFY(text != 0); + QCOMPARE(text->width(), qreal(40.)); + QVERIFY(text->width() < text->height()); + + QDeclarativeItemPrivate::get(rect)->setState("state1"); + + QVERIFY(text->width() > 41); + QVERIFY(text->width() > text->height()); +} + +void tst_qdeclarativestates::illegalObjectCreation() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent component(&engine, SRCDIR "/data/illegalObj.qml"); + QList errors = component.errors(); + QVERIFY(errors.count() == 1); + const QDeclarativeError &error = errors.at(0); + QCOMPARE(error.line(), 9); + QCOMPARE(error.column(), 23); + QCOMPARE(error.description().toUtf8().constData(), "PropertyChanges does not support creating state-specific objects."); +} + +void tst_qdeclarativestates::whenOrdering() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/whenOrdering.qml"); + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QCOMPARE(rectPrivate->state(), QLatin1String("")); + rect->setProperty("condition2", true); + QCOMPARE(rectPrivate->state(), QLatin1String("state2")); + rect->setProperty("condition1", true); + QCOMPARE(rectPrivate->state(), QLatin1String("state1")); + rect->setProperty("condition2", false); + QCOMPARE(rectPrivate->state(), QLatin1String("state1")); + rect->setProperty("condition2", true); + QCOMPARE(rectPrivate->state(), QLatin1String("state1")); + rect->setProperty("condition1", false); + rect->setProperty("condition2", false); + QCOMPARE(rectPrivate->state(), QLatin1String("")); +} + +void tst_qdeclarativestates::urlResolution() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/urlResolution.qml"); + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + + QDeclarativeItem *myType = rect->findChild("MyType"); + QDeclarativeImage *image1 = rect->findChild("image1"); + QDeclarativeImage *image2 = rect->findChild("image2"); + QDeclarativeImage *image3 = rect->findChild("image3"); + QVERIFY(myType != 0 && image1 != 0 && image2 != 0 && image3 != 0); + + QDeclarativeItemPrivate::get(myType)->setState("SetImageState"); + QUrl resolved = QUrl::fromLocalFile(SRCDIR "/data/Implementation/images/qt-logo.png"); + QCOMPARE(image1->source(), resolved); + QCOMPARE(image2->source(), resolved); + QCOMPARE(image3->source(), resolved); +} + +void tst_qdeclarativestates::unnamedWhen() +{ + QDeclarativeEngine engine; + + QDeclarativeComponent c(&engine, SRCDIR "/data/unnamedWhen.qml"); + QDeclarativeRectangle *rect = qobject_cast(c.create()); + QVERIFY(rect != 0); + QDeclarativeItemPrivate *rectPrivate = QDeclarativeItemPrivate::get(rect); + + QCOMPARE(rectPrivate->state(), QLatin1String("")); + QCOMPARE(rect->property("stateString").toString(), QLatin1String("")); + rect->setProperty("triggerState", true); + QCOMPARE(rectPrivate->state(), QLatin1String("anonymousState1")); + QCOMPARE(rect->property("stateString").toString(), QLatin1String("inState")); + rect->setProperty("triggerState", false); + QCOMPARE(rectPrivate->state(), QLatin1String("")); + QCOMPARE(rect->property("stateString").toString(), QLatin1String("")); +} + +QTEST_MAIN(tst_qdeclarativestates) + +#include "tst_qdeclarativestates.moc"