kwin/autotests/libkwineffects/timelinetest.cpp
Vlad Zahorodnii f3b291bce0 Make TimeLine API ergonomic with presentation timestamps
Currently, if you want to use TimeLine, you need to track the last
presentation timestamp which boils down to carrying some boilerplate
code.

The current situation can be improved by making TimeLine work with
presentation timestamps.

Part-of: <https://invent.kde.org/plasma/kwin/-/merge_requests/2473>
2022-05-26 17:10:07 +00:00

415 lines
13 KiB
C++

/*
KWin - the KDE window manager
This file is part of the KDE project.
SPDX-FileCopyrightText: 2018 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include <kwineffects.h>
#include <QtTest>
using namespace std::chrono_literals;
// FIXME: Delete it in the future.
Q_DECLARE_METATYPE(std::chrono::milliseconds)
class TimeLineTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testUpdateForward();
void testUpdateBackward();
void testUpdateFinished();
void testToggleDirection();
void testReset();
void testSetElapsed_data();
void testSetElapsed();
void testSetDuration();
void testSetDurationRetargeting();
void testSetDurationRetargetingSmallDuration();
void testRunning();
void testStrictRedirectSourceMode_data();
void testStrictRedirectSourceMode();
void testRelaxedRedirectSourceMode_data();
void testRelaxedRedirectSourceMode();
void testStrictRedirectTargetMode_data();
void testStrictRedirectTargetMode();
void testRelaxedRedirectTargetMode_data();
void testRelaxedRedirectTargetMode();
};
void TimeLineTest::testUpdateForward()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
// 0/1000
timeLine.advance(0ms);
QCOMPARE(timeLine.value(), 0.0);
QVERIFY(!timeLine.done());
// 100/1000
timeLine.advance(100ms);
QCOMPARE(timeLine.value(), 0.1);
QVERIFY(!timeLine.done());
// 400/1000
timeLine.advance(400ms);
QCOMPARE(timeLine.value(), 0.4);
QVERIFY(!timeLine.done());
// 900/1000
timeLine.advance(900ms);
QCOMPARE(timeLine.value(), 0.9);
QVERIFY(!timeLine.done());
// 1000/1000
timeLine.advance(3000ms);
QCOMPARE(timeLine.value(), 1.0);
QVERIFY(timeLine.done());
}
void TimeLineTest::testUpdateBackward()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Backward);
timeLine.setEasingCurve(QEasingCurve::Linear);
// 0/1000
timeLine.advance(0ms);
QCOMPARE(timeLine.value(), 1.0);
QVERIFY(!timeLine.done());
// 100/1000
timeLine.advance(100ms);
QCOMPARE(timeLine.value(), 0.9);
QVERIFY(!timeLine.done());
// 400/1000
timeLine.advance(400ms);
QCOMPARE(timeLine.value(), 0.6);
QVERIFY(!timeLine.done());
// 900/1000
timeLine.advance(900ms);
QCOMPARE(timeLine.value(), 0.1);
QVERIFY(!timeLine.done());
// 1000/1000
timeLine.advance(3000ms);
QCOMPARE(timeLine.value(), 0.0);
QVERIFY(timeLine.done());
}
void TimeLineTest::testUpdateFinished()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.advance(0ms);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(1000ms);
QCOMPARE(timeLine.value(), 1.0);
QVERIFY(timeLine.done());
timeLine.advance(1042ms);
QCOMPARE(timeLine.value(), 1.0);
QVERIFY(timeLine.done());
}
void TimeLineTest::testToggleDirection()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(0ms);
QCOMPARE(timeLine.value(), 0.0);
QVERIFY(!timeLine.done());
timeLine.advance(600ms);
QCOMPARE(timeLine.value(), 0.6);
QVERIFY(!timeLine.done());
timeLine.toggleDirection();
QCOMPARE(timeLine.value(), 0.6);
QVERIFY(!timeLine.done());
timeLine.advance(800ms);
QCOMPARE(timeLine.value(), 0.4);
QVERIFY(!timeLine.done());
timeLine.advance(3000ms);
QCOMPARE(timeLine.value(), 0.0);
QVERIFY(timeLine.done());
}
void TimeLineTest::testReset()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(0ms);
timeLine.advance(1000ms);
QCOMPARE(timeLine.value(), 1.0);
QVERIFY(timeLine.done());
timeLine.reset();
QCOMPARE(timeLine.value(), 0.0);
QVERIFY(!timeLine.done());
}
void TimeLineTest::testSetElapsed_data()
{
QTest::addColumn<std::chrono::milliseconds>("duration");
QTest::addColumn<std::chrono::milliseconds>("elapsed");
QTest::addColumn<std::chrono::milliseconds>("expectedElapsed");
QTest::addColumn<bool>("expectedDone");
QTest::addColumn<bool>("initiallyDone");
QTest::newRow("Less than duration, not finished") << 1000ms << 300ms << 300ms << false << false;
QTest::newRow("Less than duration, finished") << 1000ms << 300ms << 300ms << false << true;
QTest::newRow("Greater than duration, not finished") << 1000ms << 3000ms << 1000ms << true << false;
QTest::newRow("Greater than duration, finished") << 1000ms << 3000ms << 1000ms << true << true;
QTest::newRow("Equal to duration, not finished") << 1000ms << 1000ms << 1000ms << true << false;
QTest::newRow("Equal to duration, finished") << 1000ms << 1000ms << 1000ms << true << true;
}
void TimeLineTest::testSetElapsed()
{
QFETCH(std::chrono::milliseconds, duration);
QFETCH(std::chrono::milliseconds, elapsed);
QFETCH(std::chrono::milliseconds, expectedElapsed);
QFETCH(bool, expectedDone);
QFETCH(bool, initiallyDone);
KWin::TimeLine timeLine(duration, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(0ms);
if (initiallyDone) {
timeLine.advance(duration);
QVERIFY(timeLine.done());
}
timeLine.setElapsed(elapsed);
QCOMPARE(timeLine.elapsed(), expectedElapsed);
QCOMPARE(timeLine.done(), expectedDone);
}
void TimeLineTest::testSetDuration()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
QCOMPARE(timeLine.duration(), 1000ms);
timeLine.setDuration(3000ms);
QCOMPARE(timeLine.duration(), 3000ms);
}
void TimeLineTest::testSetDurationRetargeting()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(0ms);
timeLine.advance(500ms);
QCOMPARE(timeLine.value(), 0.5);
QVERIFY(!timeLine.done());
timeLine.setDuration(3000ms);
QCOMPARE(timeLine.value(), 0.5);
QVERIFY(!timeLine.done());
}
void TimeLineTest::testSetDurationRetargetingSmallDuration()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(0ms);
timeLine.advance(999ms);
QCOMPARE(timeLine.value(), 0.999);
QVERIFY(!timeLine.done());
timeLine.setDuration(3ms);
QCOMPARE(timeLine.value(), 1.0);
QVERIFY(timeLine.done());
}
void TimeLineTest::testRunning()
{
KWin::TimeLine timeLine(1000ms, KWin::TimeLine::Forward);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.advance(0ms);
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
timeLine.advance(100ms);
QVERIFY(timeLine.running());
QVERIFY(!timeLine.done());
timeLine.advance(1000ms);
QVERIFY(!timeLine.running());
QVERIFY(timeLine.done());
}
void TimeLineTest::testStrictRedirectSourceMode_data()
{
QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
QTest::addColumn<qreal>("initialValue");
QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
QTest::addColumn<qreal>("finalValue");
QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 0.0;
QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 1.0;
}
void TimeLineTest::testStrictRedirectSourceMode()
{
QFETCH(KWin::TimeLine::Direction, initialDirection);
KWin::TimeLine timeLine(1000ms, initialDirection);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setSourceRedirectMode(KWin::TimeLine::RedirectMode::Strict);
QTEST(timeLine.direction(), "initialDirection");
QTEST(timeLine.value(), "initialValue");
QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Strict);
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
QFETCH(KWin::TimeLine::Direction, finalDirection);
timeLine.setDirection(finalDirection);
QTEST(timeLine.direction(), "finalDirection");
QTEST(timeLine.value(), "finalValue");
QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Strict);
QVERIFY(!timeLine.running());
QVERIFY(timeLine.done());
}
void TimeLineTest::testRelaxedRedirectSourceMode_data()
{
QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
QTest::addColumn<qreal>("initialValue");
QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
QTest::addColumn<qreal>("finalValue");
QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 1.0;
QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 0.0;
}
void TimeLineTest::testRelaxedRedirectSourceMode()
{
QFETCH(KWin::TimeLine::Direction, initialDirection);
KWin::TimeLine timeLine(1000ms, initialDirection);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setSourceRedirectMode(KWin::TimeLine::RedirectMode::Relaxed);
QTEST(timeLine.direction(), "initialDirection");
QTEST(timeLine.value(), "initialValue");
QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Relaxed);
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
QFETCH(KWin::TimeLine::Direction, finalDirection);
timeLine.setDirection(finalDirection);
QTEST(timeLine.direction(), "finalDirection");
QTEST(timeLine.value(), "finalValue");
QCOMPARE(timeLine.sourceRedirectMode(), KWin::TimeLine::RedirectMode::Relaxed);
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
}
void TimeLineTest::testStrictRedirectTargetMode_data()
{
QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
QTest::addColumn<qreal>("initialValue");
QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
QTest::addColumn<qreal>("finalValue");
QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 1.0;
QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 0.0;
}
void TimeLineTest::testStrictRedirectTargetMode()
{
QFETCH(KWin::TimeLine::Direction, initialDirection);
KWin::TimeLine timeLine(1000ms, initialDirection);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setTargetRedirectMode(KWin::TimeLine::RedirectMode::Strict);
timeLine.advance(0ms);
QTEST(timeLine.direction(), "initialDirection");
QTEST(timeLine.value(), "initialValue");
QCOMPARE(timeLine.targetRedirectMode(), KWin::TimeLine::RedirectMode::Strict);
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
timeLine.advance(1000ms);
QTEST(timeLine.value(), "finalValue");
QVERIFY(!timeLine.running());
QVERIFY(timeLine.done());
QFETCH(KWin::TimeLine::Direction, finalDirection);
timeLine.setDirection(finalDirection);
QTEST(timeLine.direction(), "finalDirection");
QTEST(timeLine.value(), "finalValue");
QVERIFY(!timeLine.running());
QVERIFY(timeLine.done());
}
void TimeLineTest::testRelaxedRedirectTargetMode_data()
{
QTest::addColumn<KWin::TimeLine::Direction>("initialDirection");
QTest::addColumn<qreal>("initialValue");
QTest::addColumn<KWin::TimeLine::Direction>("finalDirection");
QTest::addColumn<qreal>("finalValue");
QTest::newRow("forward -> backward") << KWin::TimeLine::Forward << 0.0 << KWin::TimeLine::Backward << 1.0;
QTest::newRow("backward -> forward") << KWin::TimeLine::Backward << 1.0 << KWin::TimeLine::Forward << 0.0;
}
void TimeLineTest::testRelaxedRedirectTargetMode()
{
QFETCH(KWin::TimeLine::Direction, initialDirection);
KWin::TimeLine timeLine(1000ms, initialDirection);
timeLine.setEasingCurve(QEasingCurve::Linear);
timeLine.setTargetRedirectMode(KWin::TimeLine::RedirectMode::Relaxed);
timeLine.advance(0ms);
QTEST(timeLine.direction(), "initialDirection");
QTEST(timeLine.value(), "initialValue");
QCOMPARE(timeLine.targetRedirectMode(), KWin::TimeLine::RedirectMode::Relaxed);
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
timeLine.advance(1000ms);
QTEST(timeLine.value(), "finalValue");
QVERIFY(!timeLine.running());
QVERIFY(timeLine.done());
QFETCH(KWin::TimeLine::Direction, finalDirection);
timeLine.setDirection(finalDirection);
timeLine.advance(1000ms);
QTEST(timeLine.direction(), "finalDirection");
QTEST(timeLine.value(), "finalValue");
QVERIFY(!timeLine.running());
QVERIFY(!timeLine.done());
timeLine.advance(2000ms);
QTEST(timeLine.direction(), "finalDirection");
QTEST(timeLine.value(), "initialValue");
QVERIFY(!timeLine.running());
QVERIFY(timeLine.done());
}
QTEST_MAIN(TimeLineTest)
#include "timelinetest.moc"