diff options
Diffstat (limited to 'tests/auto/quick/qquickanimations/tst_qquickanimations.cpp')
-rw-r--r-- | tests/auto/quick/qquickanimations/tst_qquickanimations.cpp | 435 |
1 files changed, 366 insertions, 69 deletions
diff --git a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp index 53216da5b7..25c8559ed3 100644 --- a/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp +++ b/tests/auto/quick/qquickanimations/tst_qquickanimations.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> #include <QtQml/qqmlengine.h> #include <QtQml/qqmlcomponent.h> @@ -41,18 +16,19 @@ #include <QtQuick/private/qquickpathinterpolator_p.h> #include <QtQuick/private/qquickitem_p.h> #include <QtQuick/private/qquicklistview_p.h> +#include <QtQuick/private/qquickframeanimation_p.h> #include <QEasingCurve> #include <limits.h> #include <math.h> -#include "../../shared/util.h" +#include <QtQuickTestUtils/private/qmlutils_p.h> class tst_qquickanimations : public QQmlDataTest { Q_OBJECT public: - tst_qquickanimations() {} + tst_qquickanimations() : QQmlDataTest(QT_QMLTEST_DATADIR) {} private slots: void initTestCase() override @@ -116,6 +92,15 @@ private slots: void fastFlickingBug(); void opacityAnimationFromZero(); void alwaysRunToEndInSequentialAnimationBug(); + void cleanupWhenRenderThreadStops(); + void changePropertiesDuringAnimation_data(); + void changePropertiesDuringAnimation(); + void infiniteLoopsWithoutFrom(); + void frameAnimation1(); + void frameAnimation2(); + void restartAnimationGroupWhenDirty(); + void restartNestedAnimationGroupWhenDirty(); + void targetsDeletedNotRemoved(); }; #define QTIMED_COMPARE(lhs, rhs) do { \ @@ -139,8 +124,8 @@ void tst_qquickanimations::simpleProperty() QCOMPARE(animation.target(), &rect); QCOMPARE(animation.property(), QLatin1String("x")); QCOMPARE(animation.to().toReal(), 200.0); - QCOMPARE(fromChangedSpy.count(), 0); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 0); + QCOMPARE(toChangedSpy.size(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -155,8 +140,8 @@ void tst_qquickanimations::simpleProperty() QCOMPARE(animation.currentTime(), 125); QCOMPARE(rect.x(),100.0); animation.setFrom(100); - QCOMPARE(fromChangedSpy.count(), 1); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 1); + QCOMPARE(toChangedSpy.size(), 1); } void tst_qquickanimations::simpleNumber() @@ -171,8 +156,8 @@ void tst_qquickanimations::simpleNumber() QCOMPARE(animation.target(), &rect); QCOMPARE(animation.property(), QLatin1String("x")); QCOMPARE(animation.to(), qreal(200)); - QCOMPARE(fromChangedSpy.count(), 0); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 0); + QCOMPARE(toChangedSpy.size(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -187,8 +172,8 @@ void tst_qquickanimations::simpleNumber() QCOMPARE(animation.currentTime(), 125); QCOMPARE(rect.x(), qreal(100)); animation.setFrom(100); - QCOMPARE(fromChangedSpy.count(), 1); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 1); + QCOMPARE(toChangedSpy.size(), 1); } void tst_qquickanimations::simpleColor() @@ -203,8 +188,8 @@ void tst_qquickanimations::simpleColor() QCOMPARE(animation.target(), &rect); QCOMPARE(animation.property(), QLatin1String("color")); QCOMPARE(animation.to(), QColor("red")); - QCOMPARE(fromChangedSpy.count(), 0); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 0); + QCOMPARE(toChangedSpy.size(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -217,18 +202,18 @@ void tst_qquickanimations::simpleColor() QVERIFY(animation.isPaused()); animation.setCurrentTime(125); QCOMPARE(animation.currentTime(), 125); - QCOMPARE(rect.color(), QColor::fromRgbF(0.498039, 0, 0.498039, 1)); + QCOMPARE(rect.color(), QColor::fromRgbF(0.498039f, 0, 0.498039f, 1)); rect.setColor(QColor("green")); animation.setFrom(QColor("blue")); QCOMPARE(animation.from(), QColor("blue")); - QCOMPARE(fromChangedSpy.count(), 1); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 1); + QCOMPARE(toChangedSpy.size(), 1); animation.restart(); QCOMPARE(rect.color(), QColor("blue")); QVERIFY(animation.isRunning()); animation.setCurrentTime(125); - QCOMPARE(rect.color(), QColor::fromRgbF(0.498039, 0, 0.498039, 1)); + QCOMPARE(rect.color(), QColor::fromRgbF(0.498039f, 0, 0.498039f, 1)); } void tst_qquickanimations::simpleRotation() @@ -244,8 +229,8 @@ void tst_qquickanimations::simpleRotation() QCOMPARE(animation.property(), QLatin1String("rotation")); QCOMPARE(animation.to(), qreal(270)); QCOMPARE(animation.direction(), QQuickRotationAnimation::Numerical); - QCOMPARE(fromChangedSpy.count(), 0); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 0); + QCOMPARE(toChangedSpy.size(), 1); animation.start(); QVERIFY(animation.isRunning()); QTest::qWait(animation.duration()); @@ -260,8 +245,8 @@ void tst_qquickanimations::simpleRotation() QCOMPARE(animation.currentTime(), 125); QCOMPARE(rect.rotation(), qreal(135)); animation.setFrom(90); - QCOMPARE(fromChangedSpy.count(), 1); - QCOMPARE(toChangedSpy.count(), 1); + QCOMPARE(fromChangedSpy.size(), 1); + QCOMPARE(toChangedSpy.size(), 1); } void tst_qquickanimations::simplePath() @@ -685,11 +670,11 @@ void tst_qquickanimations::resume() QSignalSpy spy(&animation, SIGNAL(pausedChanged(bool))); animation.pause(); - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); QVERIFY(animation.isPaused()); animation.stop(); QVERIFY(!animation.isPaused()); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); // Load QtQuick to ensure that QQuickPropertyAnimation is registered as PropertyAnimation { @@ -701,12 +686,12 @@ void tst_qquickanimations::resume() QByteArray message = "<Unknown File>: QML PropertyAnimation: setPaused() cannot be used when animation isn't running."; QTest::ignoreMessage(QtWarningMsg, message); animation.pause(); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); QVERIFY(!animation.isPaused()); animation.resume(); QVERIFY(!animation.isPaused()); QVERIFY(!animation.isRunning()); - QCOMPARE(spy.count(), 2); + QCOMPARE(spy.size(), 2); } void tst_qquickanimations::dotProperty() @@ -745,7 +730,7 @@ void tst_qquickanimations::badTypes() QScopedPointer<QObject> obj(c.create()); QVERIFY(obj.isNull()); - QCOMPARE(c.errors().count(), 1); + QCOMPARE(c.errors().size(), 1); QCOMPARE(c.errors().at(0).description(), QLatin1String("Invalid property assignment: number expected")); } @@ -757,7 +742,7 @@ void tst_qquickanimations::badTypes() QScopedPointer<QObject> obj(c.create()); QVERIFY(obj.isNull()); - QCOMPARE(c.errors().count(), 1); + QCOMPARE(c.errors().size(), 1); QCOMPARE(c.errors().at(0).description(), QLatin1String("Invalid property assignment: color expected")); } @@ -1065,12 +1050,12 @@ void tst_qquickanimations::disabledTransition() QSignalSpy runningSpy(trans, SIGNAL(runningChanged())); QQuickItemPrivate::get(rect)->setState(""); QCOMPARE(myRect->x(),qreal(200)); - QCOMPARE(runningSpy.count(), 1); //stopped -> running + QCOMPARE(runningSpy.size(), 1); //stopped -> running QVERIFY(trans->running()); QTest::qWait(300); QTIMED_COMPARE(myRect->x(),qreal(100)); QVERIFY(!trans->running()); - QCOMPARE(runningSpy.count(), 2); //running -> stopped + QCOMPARE(runningSpy.size(), 2); //running -> stopped } void tst_qquickanimations::invalidDuration() @@ -1244,7 +1229,7 @@ void tst_qquickanimations::easingProperties() QVERIFY(animObject != nullptr); QCOMPARE(animObject->easing().type(), QEasingCurve::BezierSpline); QVector<QPointF> points = animObject->easing().toCubicSpline(); - QCOMPARE(points.count(), 3); + QCOMPARE(points.size(), 3); QCOMPARE(points.at(0), QPointF(0.5, 0.2)); QCOMPARE(points.at(1), QPointF(0.13, 0.65)); QCOMPARE(points.at(2), QPointF(1.0, 1.0)); @@ -1373,7 +1358,7 @@ void tst_qquickanimations::signalOrder() colorAnimation->setDuration(duration); animation->start(); - QTRY_VERIFY(finishedSpy.count()); + QTRY_VERIFY(finishedSpy.size()); QCOMPARE(actualSignalOrder, expectedSignalOrder); } @@ -1696,7 +1681,7 @@ void tst_qquickanimations::unsetAnimatorProxyJobWindow() item.setParentItem(&dummy); QSignalSpy spy(&window, SIGNAL(sceneGraphInitialized())); window.show(); - if (spy.count() < 1) + if (spy.size() < 1) spy.wait(); QCOMPARE(proxy.job().data(), job); } @@ -1723,8 +1708,8 @@ void tst_qquickanimations::finished() QVERIFY(finishedSpy.isValid()); QVERIFY(simpleTopLevelAnimation->setProperty("running", QVariant(true))); - QTRY_COMPARE(stoppedSpy.count(), 1); - QCOMPARE(finishedSpy.count(), 1); + QTRY_COMPARE(stoppedSpy.size(), 1); + QCOMPARE(finishedSpy.size(), 1); // Test that the signal is properly revisioned and hence accessible from QML. QCOMPARE(root->property("finishedUsableInQml").toBool(), true); @@ -1751,9 +1736,9 @@ void tst_qquickanimations::finished() QObject *transitionRect = root->property("transitionRect").value<QObject*>(); QVERIFY(transitionRect); QVERIFY(transitionRect->setProperty("state", QVariant(QLatin1String("go")))); - QTRY_COMPARE(runningChangedSpy.count(), 1); - QCOMPARE(stoppedSpy.count(), 0); - QCOMPARE(finishedSpy.count(), 0); + QTRY_COMPARE(runningChangedSpy.size(), 1); + QCOMPARE(stoppedSpy.size(), 0); + QCOMPARE(finishedSpy.size(), 0); } // Test that finished() is not emitted for animations within a Behavior. @@ -1770,8 +1755,8 @@ void tst_qquickanimations::finished() QVERIFY(root->setProperty("bar", QVariant(1.0))); QTRY_COMPARE(root->property("bar").toReal(), 1.0); - QCOMPARE(stoppedSpy.count(), 0); - QCOMPARE(finishedSpy.count(), 0); + QCOMPARE(stoppedSpy.size(), 0); + QCOMPARE(finishedSpy.size(), 0); } } @@ -1862,9 +1847,8 @@ void tst_qquickanimations::fastFlickingBug() void tst_qquickanimations::opacityAnimationFromZero() { - if ((QGuiApplication::platformName() == QLatin1String("offscreen")) - || (QGuiApplication::platformName() == QLatin1String("minimal"))) - QSKIP("Skipping due to grabWindow not functional on offscreen/minimimal platforms"); + if (QGuiApplication::platformName() == QLatin1String("minimal")) + QSKIP("Skipping due to grabWindow not functional on minimal platforms"); // not easy to verify this in threaded render loop // since it's difficult to capture the first frame when scene graph @@ -1898,7 +1882,7 @@ void tst_qquickanimations::opacityAnimationFromZero() void tst_qquickanimations::alwaysRunToEndInSequentialAnimationBug() { - QQuickView view(QUrl::fromLocalFile("data/alwaysRunToEndInSequentialAnimationBug.qml")); + QQuickView view(testFileUrl("alwaysRunToEndInSequentialAnimationBug.qml")); view.show(); QVERIFY(QTest::qWaitForWindowExposed(&view)); @@ -1998,6 +1982,319 @@ void tst_qquickanimations::alwaysRunToEndInSequentialAnimationBug() QCOMPARE(whiteRect->property("opacity").value<qreal>(),1.0); } +void tst_qquickanimations::cleanupWhenRenderThreadStops() +{ + QQuickView view(testFileUrl("cleanupWhenRenderThreadStops.qml")); + view.show(); + view.setPersistentGraphics(false); + view.setPersistentSceneGraph(false); + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QTest::qWait(50); + view.hide(); + view.show(); + QVERIFY(QTest::qWaitForWindowExposed(&view)); +} + +// This will be called each frame and should return true for the test to pass. +typedef std::function<bool(QQuickItem *, QString &)> PropertyValidatorFunc; +Q_DECLARE_METATYPE(PropertyValidatorFunc) + +void tst_qquickanimations::changePropertiesDuringAnimation_data() +{ + QTest::addColumn<int>("loops"); + QTest::addColumn<QString>("propertyName"); + QTest::addColumn<qreal>("newValue"); + QTest::addColumn<PropertyValidatorFunc>("propertyValidatorFunc"); + + // Use a value large enough to ensure that the animation is running for the duration of + // the test. We test both infinite and non-infinite loop counts. + const int largeLoopCount = 100; + + const auto fromValidator = PropertyValidatorFunc([](QQuickItem *rect, QString &failureMessage){ + if (rect->x() >= 0) + return true; + QDebug(&failureMessage) << "Expected x of rect to never go below new \"from\" value of 0, but it's" << rect->x(); + return false; + }); + QTest::newRow("from") << largeLoopCount << "from" << 0.0 << fromValidator; + QTest::newRow("from,infinite") << int(QQuickAbstractAnimation::Infinite) << "from" << 0.0 << fromValidator; + + const auto toValidator = PropertyValidatorFunc([](QQuickItem *rect, QString &failureMessage){ + if (rect->x() <= 100) + return true; + QDebug(&failureMessage) << "Expected x of rect to never go above new \"to\" value of 100, but it's" << rect->x(); + return false; + }); + QTest::newRow("to") << largeLoopCount << "to" << 100.0 << toValidator; + QTest::newRow("to,infinite") << int(QQuickAbstractAnimation::Infinite) << "to" << 100.0 << toValidator; + + // Duration and easing.type would be difficult/flaky to test in CI so they're left out here. +} + +// Tests that changing a NumberAnimation's properties while it's running will result +// in those changes being picked up on the next loop. This is new behavior introduced +// in Qt 6.4. +void tst_qquickanimations::changePropertiesDuringAnimation() +{ + QFETCH(int, loops); + QFETCH(QString, propertyName); + QFETCH(qreal, newValue); + QFETCH(PropertyValidatorFunc, propertyValidatorFunc); + + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("changePropertiesDuringAnimation.qml")); + QScopedPointer<QQuickItem> rootItem(qobject_cast<QQuickItem*>(component.createWithInitialProperties({{ "loops", loops }}))); + QVERIFY2(!component.isError(), qPrintable(component.errorString())); + + auto numberAnimation = rootItem->property("numberAnimation").value<QQuickNumberAnimation*>(); + QVERIFY(numberAnimation); + QCOMPARE(numberAnimation->from(), -100); + QCOMPARE(numberAnimation->to(), rootItem->width()); + + // Start the animation. + numberAnimation->start(); + QVERIFY(numberAnimation->isRunning()); + + int loopCountBeforeModification = 0; + // Ensure that it's past the first loop so that we can check that it resumes + // from that loop after "restarting". + QTRY_VERIFY(numberAnimation->qtAnimation()->currentLoop() >= 1); + loopCountBeforeModification = numberAnimation->qtAnimation()->currentLoop(); + + QSignalSpy startedSpy(numberAnimation, SIGNAL(started())); + QVERIFY(startedSpy.isValid()); + QSignalSpy stoppedSpy(numberAnimation, SIGNAL(stopped())); + QVERIFY(stoppedSpy.isValid()); + + // Modify the property. + // QQuickPropertyAnimation has a setProperty function of its own, and we don't want to call it, hence the cast. + QVERIFY(static_cast<QObject*>(numberAnimation)->setProperty(propertyName.toLatin1().constData(), QVariant(newValue))); + + // Make sure we've reached the end of the animation. + auto rect = rootItem->property("rect").value<QQuickItem*>(); + QVERIFY(rect); + // Ensure that we've passed the loop on which we modified the property, while also checking + // that currentLoop never gets reset to 0. We can't just use QTRY_VERIFY + // for this, because it could start at 0 and then pass loopCountBeforeModification; + // we need to ensure that it never goes below loopCountBeforeModification. + while (numberAnimation->qtAnimation()->currentLoop() < loopCountBeforeModification + 1) { + QVERIFY2(numberAnimation->qtAnimation()->currentLoop() >= loopCountBeforeModification, + qPrintable(QString::fromLatin1("Expected currentLoop to be larger than %1, but it's %2") + .arg(loopCountBeforeModification).arg(numberAnimation->qtAnimation()->currentLoop()))); + QTest::qWait(0); + } + + // Now that we know the modification should have been taken into account, + // check that the animated property never gets set to a value that we wouldn't expect after the change. + const int previousLoop = numberAnimation->qtAnimation()->currentLoop(); + QString failureMessage; + while (numberAnimation->qtAnimation()->currentLoop() < previousLoop + 1) { + if (!propertyValidatorFunc(rect, failureMessage)) + QFAIL(qPrintable(failureMessage)); + QTest::qWait(0); + } + + // The started and stopped signals should not be emitted when adapting to changes + // mid-animation. + if (loops != QQuickAbstractAnimation::Infinite) + QVERIFY(numberAnimation->qtAnimation()->currentLoop() < numberAnimation->loops()); + QCOMPARE(startedSpy.size(), 0); + QCOMPARE(stoppedSpy.size(), 0); +} + +void tst_qquickanimations::infiniteLoopsWithoutFrom() +{ + // This test checks QTBUG-84375 + QQuickView view(testFileUrl("infiniteAnimationWithoutFrom.qml")); + view.show(); + + QVERIFY(QTest::qWaitForWindowExposed(&view)); + QVERIFY(view.rootObject()); + + QObject *root = view.rootObject(); + QQuickAbstractAnimation *animation = root->findChild<QQuickAbstractAnimation *>("anim"); + QVERIFY(animation); + QQuickRectangle *rectangle = root->findChild<QQuickRectangle *>("rect"); + QVERIFY(rectangle); + + qreal prevRotation = rectangle->rotation(); + int numsCrossedZero = 0; + connect(rectangle, &QQuickRectangle::rotationChanged, this, [&]() { + const auto rotation = rectangle->rotation(); + // We take a large range of (180; 360] here, because the animation in + // the test runs for a short time, and so there can be huge gaps between + // rotation values. + const bool prevRotationOldLoop = prevRotation > 180.0 && prevRotation <= 360.0; + const bool currRotationNewLoop = rotation >= 0.0 && rotation <= 180.0; + if (prevRotationOldLoop && currRotationNewLoop) + numsCrossedZero++; + prevRotation = rotation; + }); + + // The logic in lamdba function above requires at least two positions in + // a rotation animation - one in [0; 180] range, and another in (180; 360] + // range + animation->start(); + animation->pause(); + QCOMPARE(numsCrossedZero, 0); + animation->setCurrentTime(40); + animation->setCurrentTime(90); + QCOMPARE(numsCrossedZero, 0); + animation->setCurrentTime(140); + animation->setCurrentTime(190); + QCOMPARE(numsCrossedZero, 1); + animation->setCurrentTime(240); + animation->setCurrentTime(290); + QCOMPARE(numsCrossedZero, 2); + + animation->stop(); +} + +void tst_qquickanimations::frameAnimation1() +{ + QQuickFrameAnimation frameAnimation; + QVERIFY(!frameAnimation.isRunning()); + QVERIFY(!frameAnimation.isPaused()); + QCOMPARE(frameAnimation.currentFrame(), 0); + QCOMPARE(frameAnimation.frameTime(), 0); + QCOMPARE(frameAnimation.smoothFrameTime(), 0); + QCOMPARE(frameAnimation.elapsedTime(), 0); + + frameAnimation.start(); + QVERIFY(frameAnimation.isRunning()); + QVERIFY(!frameAnimation.isPaused()); + frameAnimation.pause(); + QVERIFY(frameAnimation.isRunning()); + QVERIFY(frameAnimation.isPaused()); + frameAnimation.resume(); + QVERIFY(frameAnimation.isRunning()); + QVERIFY(!frameAnimation.isPaused()); + frameAnimation.stop(); + QVERIFY(!frameAnimation.isRunning()); + QVERIFY(!frameAnimation.isPaused()); + frameAnimation.restart(); + QVERIFY(frameAnimation.isRunning()); + QVERIFY(!frameAnimation.isPaused()); +} + +void tst_qquickanimations::frameAnimation2() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("frameAnimation.qml")); + QScopedPointer<QObject> obj(c.create()); + auto *root = qobject_cast<QQuickRectangle*>(obj.data()); + QVERIFY(root); + + QQuickFrameAnimation *frameAnimation = root->findChild<QQuickFrameAnimation*>(); + QVERIFY(frameAnimation); + QSignalSpy spy(frameAnimation, SIGNAL(triggered())); + + // Start the animation and wait at least 1 frame + frameAnimation->start(); + QVERIFY(frameAnimation->isRunning()); + QVERIFY(spy.wait(500)); + QVERIFY(frameAnimation->currentFrame() > 0); + QVERIFY(frameAnimation->frameTime() > 0); + QVERIFY(frameAnimation->smoothFrameTime() > 0); + QVERIFY(frameAnimation->elapsedTime() > 0); + + // Stopping and reseting should return currentFrame back to 0 + frameAnimation->stop(); + frameAnimation->reset(); + QCOMPARE(frameAnimation->currentFrame(), 0); + + // Start and wait so the animation runs into frame 3 and pauses + frameAnimation->start(); + QTRY_VERIFY(frameAnimation->isPaused()); + QVERIFY(frameAnimation->currentFrame() >= 3); + + // Then resume the animation + frameAnimation->resume(); + QVERIFY(!frameAnimation->isPaused()); + QVERIFY(spy.wait(500)); + QVERIFY(frameAnimation->currentFrame() > 3); +} + +//QTBUG-110589 +void tst_qquickanimations::restartAnimationGroupWhenDirty() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("restartAnimationGroupWhenDirty.qml")); + QScopedPointer<QObject> obj(c.create()); + auto *root = qobject_cast<QQuickRectangle*>(obj.data()); + QVERIFY2(root, qPrintable(c.errorString())); + + QQuickSequentialAnimation *seqAnim0 = root->findChild<QQuickSequentialAnimation*>("seqAnim0"); + QVERIFY(seqAnim0); + QQuickRectangle *target0 = root->findChild<QQuickRectangle*>("target0"); + QVERIFY(target0); + QQuickParallelAnimation *parAnim0 = root->findChild<QQuickParallelAnimation*>("parAnim0"); + QVERIFY(parAnim0); + QQuickRectangle *target1 = root->findChild<QQuickRectangle*>("target1"); + QVERIFY(target1); + + QTRY_VERIFY(seqAnim0->isPaused()); + QTRY_VERIFY(parAnim0->isPaused()); + QTRY_VERIFY(target0->x() > 140); + QTRY_VERIFY(target1->x() > 140); + seqAnim0->resume(); + parAnim0->resume(); + QTRY_VERIFY(target0->property("onFinishedCalled").value<bool>()); + QTRY_VERIFY(target1->property("onFinishedCalled").value<bool>()); + QTRY_COMPARE(target0->x(), 140); + QTRY_COMPARE(target1->x(), 140); +} + +//QTBUG-95840 +void tst_qquickanimations::restartNestedAnimationGroupWhenDirty() +{ + QQmlEngine engine; + QQmlComponent c(&engine, testFileUrl("restartNestedAnimationGroupWhenDirty.qml")); + QScopedPointer<QObject> obj(c.create()); + auto *root = qobject_cast<QQuickRectangle*>(obj.data()); + QVERIFY2(root, qPrintable(c.errorString())); + + QQuickSequentialAnimation *seqAnim0 = root->findChild<QQuickSequentialAnimation*>("seqAnim0"); + QVERIFY(seqAnim0); + QQuickRectangle *target0 = root->findChild<QQuickRectangle*>("target0"); + QVERIFY(target0); + QQuickParallelAnimation *parAnim0 = root->findChild<QQuickParallelAnimation*>("parAnim0"); + QVERIFY(parAnim0); + QQuickRectangle *target1 = root->findChild<QQuickRectangle*>("target1"); + QVERIFY(target1); + + QTRY_VERIFY(seqAnim0->isPaused()); + QTRY_VERIFY(parAnim0->isPaused()); + QTRY_VERIFY(target0->x() > 140); + QTRY_VERIFY(target1->x() > 140); + seqAnim0->resume(); + parAnim0->resume(); + QTRY_VERIFY(target0->property("onFinishedCalled").value<bool>()); + QTRY_VERIFY(target1->property("onFinishedCalled").value<bool>()); + QTRY_COMPARE(target0->x(), 140); + QTRY_COMPARE(target1->x(), 140); +} + +void tst_qquickanimations::targetsDeletedNotRemoved() +{ + QQmlEngine engine; + QQmlComponent component(&engine, testFileUrl("targetsDeletedWithoutRemoval.qml")); + QScopedPointer<QObject> obj(component.create()); + QVERIFY2(obj.get(), qPrintable(component.errorString())); + { + QQmlListReference ref(obj.get(), "targets"); + QVERIFY(ref.isValid()); + QCOMPARE(ref.size(), 1); + QTRY_COMPARE(ref.at(0), nullptr); + } + { + QQmlListReference ref(obj.get(), "animTargets"); + QVERIFY(ref.isValid()); + QCOMPARE(ref.size(), 1); + QCOMPARE(ref.at(0), nullptr); + } +} + QTEST_MAIN(tst_qquickanimations) #include "tst_qquickanimations.moc" |