File indexing completed on 2024-10-06 05:12:52

0001 /* This file is part of Kairo Timer
0002 
0003    SPDX-FileCopyrightText: 2016 (c) Kevin Ottens <ervin@kde.org>
0004 
0005    SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 
0007 */
0008 
0009 #include <QtTest>
0010 #include <QSignalSpy>
0011 
0012 #include <memory>
0013 
0014 #include "timercontrol.h"
0015 
0016 class TimerControlTest : public QObject
0017 {
0018     Q_OBJECT
0019 private slots:
0020     void shouldHaveDefaultState()
0021     {
0022         // GIVEN
0023         auto control = std::make_unique<TimerControl>();
0024 
0025         // THEN
0026         QCOMPARE(control->model(), TimerModel{});
0027         QCOMPARE(control->text(), QString());
0028         QCOMPARE(control->value(), 0);
0029         QCOMPARE(control->formattedValue(), QStringLiteral("00:00.0"));
0030         QCOMPARE(control->duration(), -1);
0031         QCOMPARE(control->isRunning(), false);
0032     }
0033 
0034     void shouldDeriveValuesFromModel_data()
0035     {
0036         QTest::addColumn<TimerModel>("model");
0037         QTest::addColumn<QString>("expectedText");
0038         QTest::addColumn<int>("expectedValue");
0039         QTest::addColumn<QString>("expectedFormattedValue");
0040         QTest::addColumn<int>("expectedDuration");
0041 
0042         QTest::newRow("invalid") << TimerModel{} << QString() << 0 << QStringLiteral("00:00.0") <<-1;
0043         QTest::newRow("countdown") << TimerModel{"foo", 10000} << "foo" << 10000 << QStringLiteral("00:10.0") << 10000;
0044         QTest::newRow("countdown") << TimerModel{"baz", 1050300} << "baz" << 1050300 << QStringLiteral("17:30.3") << 1050300;
0045         QTest::newRow("countdown") << TimerModel{"baz", 34570900} << "baz" << 34570900 << QStringLiteral("576:10.9") << 34570900;
0046         QTest::newRow("stopwatch") << TimerModel{"bar"} << "bar" << 0 << QStringLiteral("00:00.0") << 0;
0047     }
0048 
0049     void shouldDeriveValuesFromModel()
0050     {
0051         // GIVEN
0052         auto control = std::make_unique<TimerControl>();
0053         auto modelSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::modelChanged);
0054         auto textSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::textChanged);
0055         auto valueSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::valueChanged);
0056         auto durationSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::durationChanged);
0057 
0058         QFETCH(TimerModel, model);
0059         QFETCH(QString, expectedText);
0060         QFETCH(int, expectedValue);
0061         QFETCH(QString, expectedFormattedValue);
0062         QFETCH(int, expectedDuration);
0063 
0064         // WHEN
0065         control->setModel(model);
0066 
0067         // THEN
0068         QCOMPARE(control->model(), model);
0069         QCOMPARE(control->text(), expectedText);
0070         QCOMPARE(control->value(), expectedValue);
0071         QCOMPARE(control->formattedValue(), expectedFormattedValue);
0072         QCOMPARE(control->duration(), expectedDuration);
0073 
0074         if (model.isValid()) {
0075             QCOMPARE(modelSpy->size(), 1);
0076             QCOMPARE(modelSpy->takeFirst().first().value<TimerModel>(), model);
0077 
0078             QCOMPARE(textSpy->size(), 1);
0079             QCOMPARE(textSpy->takeFirst().first().toString(), expectedText);
0080 
0081             if (model.duration() >= 0) {
0082                 QCOMPARE(durationSpy->size(), 1);
0083                 QCOMPARE(durationSpy->takeFirst().first().toInt(), expectedDuration);
0084             } else {
0085                 QCOMPARE(durationSpy->size(), 0);
0086             }
0087 
0088             if (model.duration() != 0) {
0089                 QCOMPARE(valueSpy->size(), 1);
0090                 QCOMPARE(valueSpy->takeFirst().first().toInt(), expectedValue);
0091             } else {
0092                 QCOMPARE(valueSpy->size(), 0);
0093             }
0094         } else {
0095             QCOMPARE(textSpy->size(), 0);
0096             QCOMPARE(valueSpy->size(), 0);
0097             QCOMPARE(durationSpy->size(), 0);
0098         }
0099 
0100         // WHEN
0101         control->setModel(model);
0102 
0103         // THEN
0104         QCOMPARE(textSpy->size(), 0);
0105         QCOMPARE(valueSpy->size(), 0);
0106         QCOMPARE(durationSpy->size(), 0);
0107     }
0108 
0109     void shouldDeriveValuesFromMovedModel_data()
0110     {
0111         shouldDeriveValuesFromModel_data();
0112     }
0113 
0114     void shouldDeriveValuesFromMovedModel()
0115     {
0116         // GIVEN
0117         auto control = std::make_unique<TimerControl>();
0118         auto textSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::textChanged);
0119         auto valueSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::valueChanged);
0120         auto durationSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::durationChanged);
0121 
0122         QFETCH(TimerModel, model);
0123         QFETCH(QString, expectedText);
0124         QFETCH(int, expectedValue);
0125         QFETCH(QString, expectedFormattedValue);
0126         QFETCH(int, expectedDuration);
0127 
0128         // WHEN
0129         auto copy = model;
0130         control->setModel(std::move(copy)); // This should move it in place
0131 
0132         // THEN
0133         QCOMPARE(control->model(), model);
0134         QCOMPARE(control->text(), expectedText);
0135         QCOMPARE(control->value(), expectedValue);
0136         QCOMPARE(control->formattedValue(), expectedFormattedValue);
0137         QCOMPARE(control->duration(), expectedDuration);
0138 
0139         if (model.isValid()) {
0140             QCOMPARE(textSpy->size(), 1);
0141             QCOMPARE(textSpy->takeFirst().first().toString(), expectedText);
0142 
0143             if (model.duration() >= 0) {
0144                 QCOMPARE(durationSpy->size(), 1);
0145                 QCOMPARE(durationSpy->takeFirst().first().toInt(), expectedDuration);
0146             } else {
0147                 QCOMPARE(durationSpy->size(), 0);
0148             }
0149 
0150             if (model.duration() != 0) {
0151                 QCOMPARE(valueSpy->size(), 1);
0152                 QCOMPARE(valueSpy->takeFirst().first().toInt(), expectedValue);
0153             } else {
0154                 QCOMPARE(valueSpy->size(), 0);
0155             }
0156         } else {
0157             QCOMPARE(textSpy->size(), 0);
0158             QCOMPARE(valueSpy->size(), 0);
0159         }
0160 
0161         // WHEN
0162         control->setModel(std::move(model));
0163 
0164         // THEN
0165         QCOMPARE(textSpy->size(), 0);
0166         QCOMPARE(valueSpy->size(), 0);
0167         QCOMPARE(durationSpy->size(), 0);
0168     }
0169 
0170     void shouldDoNothingWhileRunningInvalid()
0171     {
0172         // GIVEN
0173         auto control = std::make_unique<TimerControl>();
0174         auto textSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::textChanged);
0175         auto valueSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::valueChanged);
0176         auto durationSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::durationChanged);
0177         auto runningSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::runningChanged);
0178         auto finishedSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::timerFinished);
0179         control->setModel(TimerModel{});
0180 
0181         // WHEN
0182         control->setRunning(true);
0183         QTest::qWait(100);
0184 
0185         // THEN
0186         QCOMPARE(control->isRunning(), true);
0187         QCOMPARE(textSpy->size(), 0);
0188         QCOMPARE(valueSpy->size(), 0);
0189         QCOMPARE(durationSpy->size(), 0);
0190         QCOMPARE(runningSpy->size(), 1);
0191         QCOMPARE(runningSpy->takeFirst().first().toBool(), true);
0192         QCOMPARE(finishedSpy->size(), 1);
0193     }
0194 
0195     void shouldRunCountdown()
0196     {
0197         // GIVEN
0198         auto control = std::make_unique<TimerControl>();
0199         auto textSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::textChanged);
0200         auto valueSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::valueChanged);
0201         auto durationSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::durationChanged);
0202         auto runningSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::runningChanged);
0203         auto finishedSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::timerFinished);
0204 
0205         control->setModel(TimerModel{"rest", 100});
0206         textSpy->clear();
0207         valueSpy->clear();
0208         durationSpy->clear();
0209 
0210         // WHEN
0211         control->setRunning(true);
0212         QTest::qWait(105);
0213 
0214         // THEN
0215         QCOMPARE(control->isRunning(), true);
0216         QCOMPARE(textSpy->size(), 0);
0217         QCOMPARE(durationSpy->size(), 0);
0218         QCOMPARE(valueSpy->size(), 10);
0219         for (int value = 100; value != 0; value -= 10) {
0220             QCOMPARE(valueSpy->takeFirst().first().toInt(), value - 10);
0221         }
0222         QCOMPARE(runningSpy->size(), 1);
0223         QCOMPARE(runningSpy->takeFirst().first().toBool(), true);
0224         QCOMPARE(finishedSpy->size(), 1);
0225     }
0226 
0227     void shouldRunStopwatch()
0228     {
0229         // GIVEN
0230         auto control = std::make_unique<TimerControl>();
0231         auto textSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::textChanged);
0232         auto valueSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::valueChanged);
0233         auto durationSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::durationChanged);
0234         auto runningSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::runningChanged);
0235         auto finishedSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::timerFinished);
0236 
0237         control->setModel(TimerModel{"run"});
0238         textSpy->clear();
0239         valueSpy->clear();
0240         durationSpy->clear();
0241 
0242         // WHEN
0243         control->setRunning(true);
0244         QTest::qWait(105);
0245         control->setRunning(false);
0246 
0247         // THEN
0248         QCOMPARE(control->isRunning(), false);
0249         QCOMPARE(textSpy->size(), 0);
0250         QCOMPARE(durationSpy->size(), 0);
0251         QCOMPARE(valueSpy->size(), 10);
0252         for (int value = 0; value != 100; value += 10) {
0253             QCOMPARE(valueSpy->takeFirst().first().toInt(), value + 10);
0254         }
0255         QCOMPARE(runningSpy->size(), 2);
0256         QCOMPARE(runningSpy->takeFirst().first().toBool(), true);
0257         QCOMPARE(runningSpy->takeFirst().first().toBool(), false);
0258         QCOMPARE(finishedSpy->size(), 0);
0259     }
0260 
0261     void shouldKeepRunningDuringModelChanges()
0262     {
0263         // GIVEN
0264         auto control = std::make_unique<TimerControl>();
0265         auto textSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::textChanged);
0266         auto valueSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::valueChanged);
0267         auto durationSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::durationChanged);
0268         auto runningSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::runningChanged);
0269         auto finishedSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::timerFinished);
0270         auto skippedSpy = std::make_unique<QSignalSpy>(control.get(), &TimerControl::timerSkipped);
0271 
0272         control->setModel(TimerModel{"run"});
0273         textSpy->clear();
0274         valueSpy->clear();
0275         durationSpy->clear();
0276 
0277         // WHEN
0278         control->setRunning(true);
0279         QTest::qWait(25);
0280         control->setModel(TimerModel{"rest", 100});
0281         QTest::qWait(105);
0282         control->setModel(TimerModel{"run"});
0283         QTest::qWait(35);
0284         control->setModel(TimerModel{"rest again", 100});
0285         QTest::qWait(55);
0286         control->setRunning(false);
0287 
0288         // THEN
0289         QCOMPARE(control->isRunning(), false);
0290         QCOMPARE(runningSpy->size(), 2);
0291         QCOMPARE(runningSpy->takeFirst().first().toBool(), true);
0292         QCOMPARE(runningSpy->takeFirst().first().toBool(), false);
0293 
0294         QCOMPARE(textSpy->size(), 3);
0295         QCOMPARE(textSpy->takeFirst().first().toString(), QString("rest"));
0296         QCOMPARE(textSpy->takeFirst().first().toString(), QString("run"));
0297         QCOMPARE(textSpy->takeFirst().first().toString(), QString("rest again"));
0298 
0299         const auto expectedValues = QVector<int>{10, 20, 100, 90, 80, 70, 60, 50, 40, 30, 20, 10, 0, 10, 20, 30, 100, 90, 80, 70, 60, 50};
0300         auto values = QVector<int>();
0301         while (!valueSpy->isEmpty())
0302             values << valueSpy->takeFirst().first().toInt();
0303         qDebug() << values;
0304         qDebug() << expectedValues;
0305         QCOMPARE(values, expectedValues);
0306 
0307         const auto expectedDurations = QVector<int>{100, 0, 100};
0308         auto durations = QVector<int>();
0309         while (!durationSpy->isEmpty())
0310             durations << durationSpy->takeFirst().first().toInt();
0311         qDebug() << durations;
0312         qDebug() << expectedDurations;
0313         QCOMPARE(values, expectedValues);
0314 
0315         QCOMPARE(finishedSpy->size(), 1);
0316         QCOMPARE(skippedSpy->size(), 2);
0317     }
0318 
0319     void shouldCreateModels()
0320     {
0321         // GIVEN
0322         auto control = std::make_unique<TimerControl>();
0323 
0324         // THEN
0325         auto model = TimerModel{};
0326         QCOMPARE(control->createModel(), model);
0327 
0328         model = TimerModel{"foo"};
0329         QCOMPARE(control->createModel("foo"), model);
0330 
0331         model = TimerModel{"bar", 1000};
0332         QCOMPARE(control->createModel("bar", 1000), model);
0333     }
0334 };
0335 
0336 QTEST_MAIN(TimerControlTest)
0337 
0338 #include "timercontroltest.moc"