| 1 | /**************************************************************************** | 
| 2 | ** | 
| 3 | ** Copyright (C) 2016 The Qt Company Ltd. | 
| 4 | ** Contact: https://www.qt.io/licensing/ | 
| 5 | ** | 
| 6 | ** This file is part of the test suite of the Qt Toolkit. | 
| 7 | ** | 
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ | 
| 9 | ** Commercial License Usage | 
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in | 
| 11 | ** accordance with the commercial license agreement provided with the | 
| 12 | ** Software or, alternatively, in accordance with the terms contained in | 
| 13 | ** a written agreement between you and The Qt Company. For licensing terms | 
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
| 15 | ** information use the contact form at https://www.qt.io/contact-us. | 
| 16 | ** | 
| 17 | ** GNU General Public License Usage | 
| 18 | ** Alternatively, this file may be used under the terms of the GNU | 
| 19 | ** General Public License version 3 as published by the Free Software | 
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT | 
| 21 | ** included in the packaging of this file. Please review the following | 
| 22 | ** information to ensure the GNU General Public License requirements will | 
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. | 
| 24 | ** | 
| 25 | ** $QT_END_LICENSE$ | 
| 26 | ** | 
| 27 | ****************************************************************************/ | 
| 28 |  | 
| 29 | #include <QtTest/QtTest> | 
| 30 |  | 
| 31 | #include <qeasingcurve.h> | 
| 32 |  | 
| 33 | #include <utility> // for std::move() | 
| 34 |  | 
| 35 | class tst_QEasingCurve : public QObject | 
| 36 | { | 
| 37 |     Q_OBJECT | 
| 38 | private slots: | 
| 39 |     void type(); | 
| 40 |     void propertyDefaults(); | 
| 41 |     void valueForProgress_data(); | 
| 42 |     void valueForProgress(); | 
| 43 |     void setCustomType(); | 
| 44 |     void operators(); | 
| 45 |     void properties(); | 
| 46 |     void metaTypes(); | 
| 47 |     void propertyOrderIsNotImportant(); | 
| 48 |     void bezierSpline_data(); | 
| 49 |     void bezierSpline(); | 
| 50 |     void tcbSpline_data(); | 
| 51 |     void tcbSpline(); | 
| 52 |     void testCbrtDouble(); | 
| 53 |     void testCbrtFloat(); | 
| 54 |     void cpp11(); | 
| 55 |     void quadraticEquation(); | 
| 56 |     void streamInOut_data(); | 
| 57 |     void streamInOut(); | 
| 58 | }; | 
| 59 |  | 
| 60 | void tst_QEasingCurve::type() | 
| 61 | { | 
| 62 |     { | 
| 63 |     QEasingCurve curve(QEasingCurve::Linear); | 
| 64 |     QCOMPARE(curve.period(), 0.3); | 
| 65 |     QCOMPARE(curve.amplitude(), 1.0); | 
| 66 |  | 
| 67 |     curve.setPeriod(5); | 
| 68 |     curve.setAmplitude(3); | 
| 69 |     QCOMPARE(curve.period(), 5.0); | 
| 70 |     QCOMPARE(curve.amplitude(), 3.0); | 
| 71 |  | 
| 72 |     curve.setType(QEasingCurve::InElastic); | 
| 73 |     QCOMPARE(curve.period(), 5.0); | 
| 74 |     QCOMPARE(curve.amplitude(), 3.0); | 
| 75 |     } | 
| 76 |  | 
| 77 |     { | 
| 78 |     QEasingCurve curve(QEasingCurve::InElastic); | 
| 79 |     QCOMPARE(curve.period(), 0.3); | 
| 80 |     QCOMPARE(curve.amplitude(), 1.0); | 
| 81 |     curve.setAmplitude(2); | 
| 82 |     QCOMPARE(curve.type(), QEasingCurve::InElastic); | 
| 83 |     curve.setType(QEasingCurve::Linear); | 
| 84 |     } | 
| 85 |  | 
| 86 |     { | 
| 87 |     // check bounaries | 
| 88 |     QEasingCurve curve(QEasingCurve::InCubic); | 
| 89 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QEasingCurve: Invalid curve type 9999" ); | 
| 90 |     curve.setType((QEasingCurve::Type)9999); | 
| 91 |     QCOMPARE(curve.type(), QEasingCurve::InCubic); | 
| 92 |     QTest::ignoreMessage(type: QtWarningMsg, message: "QEasingCurve: Invalid curve type -9999" ); | 
| 93 |     curve.setType((QEasingCurve::Type)-9999); | 
| 94 |     QCOMPARE(curve.type(), QEasingCurve::InCubic); | 
| 95 |     QTest::ignoreMessage(type: QtWarningMsg, message: QString::fromLatin1(str: "QEasingCurve: Invalid curve type %1" ) | 
| 96 |                         .arg(a: QEasingCurve::NCurveTypes).toLatin1().constData()); | 
| 97 |     curve.setType(QEasingCurve::NCurveTypes); | 
| 98 |     QCOMPARE(curve.type(), QEasingCurve::InCubic); | 
| 99 |     QTest::ignoreMessage(type: QtWarningMsg, message: QString::fromLatin1(str: "QEasingCurve: Invalid curve type %1" ) | 
| 100 |                         .arg(a: QEasingCurve::Custom).toLatin1().constData()); | 
| 101 |     curve.setType(QEasingCurve::Custom); | 
| 102 |     QCOMPARE(curve.type(), QEasingCurve::InCubic); | 
| 103 |     QTest::ignoreMessage(type: QtWarningMsg, message: QString::fromLatin1(str: "QEasingCurve: Invalid curve type %1" ) | 
| 104 |                         .arg(a: -1).toLatin1().constData()); | 
| 105 |     curve.setType((QEasingCurve::Type)-1); | 
| 106 |     QCOMPARE(curve.type(), QEasingCurve::InCubic); | 
| 107 |     curve.setType(QEasingCurve::Linear); | 
| 108 |     QCOMPARE(curve.type(), QEasingCurve::Linear); | 
| 109 |     curve.setType(QEasingCurve::CosineCurve); | 
| 110 |     QCOMPARE(curve.type(), QEasingCurve::CosineCurve); | 
| 111 |     } | 
| 112 | } | 
| 113 |  | 
| 114 | void tst_QEasingCurve::propertyDefaults() | 
| 115 | { | 
| 116 |     { | 
| 117 |     // checks if the defaults are correct, but also demonstrates a weakness with the API. | 
| 118 |     QEasingCurve curve(QEasingCurve::InElastic); | 
| 119 |     QCOMPARE(curve.period(), 0.3); | 
| 120 |     QCOMPARE(curve.amplitude(), 1.0); | 
| 121 |     QCOMPARE(curve.overshoot(), qreal(1.70158)); | 
| 122 |     curve.setType(QEasingCurve::InBounce); | 
| 123 |     QCOMPARE(curve.period(), 0.3); | 
| 124 |     QCOMPARE(curve.amplitude(), 1.0); | 
| 125 |     QCOMPARE(curve.overshoot(), qreal(1.70158)); | 
| 126 |     curve.setType(QEasingCurve::Linear); | 
| 127 |     QCOMPARE(curve.period(), 0.3); | 
| 128 |     QCOMPARE(curve.amplitude(), 1.0); | 
| 129 |     QCOMPARE(curve.overshoot(), qreal(1.70158)); | 
| 130 |     curve.setType(QEasingCurve::InElastic); | 
| 131 |     QCOMPARE(curve.period(), 0.3); | 
| 132 |     QCOMPARE(curve.amplitude(), 1.0); | 
| 133 |     QCOMPARE(curve.overshoot(), qreal(1.70158)); | 
| 134 |     curve.setPeriod(0.4); | 
| 135 |     curve.setAmplitude(0.6); | 
| 136 |     curve.setOvershoot(1.0); | 
| 137 |     curve.setType(QEasingCurve::Linear); | 
| 138 |     QCOMPARE(curve.period(), 0.4); | 
| 139 |     QCOMPARE(curve.amplitude(), 0.6); | 
| 140 |     QCOMPARE(curve.overshoot(), 1.0); | 
| 141 |     curve.setType(QEasingCurve::InElastic); | 
| 142 |     QCOMPARE(curve.period(), 0.4); | 
| 143 |     QCOMPARE(curve.amplitude(), 0.6); | 
| 144 |     QCOMPARE(curve.overshoot(), 1.0); | 
| 145 |     } | 
| 146 | } | 
| 147 |  | 
| 148 | typedef QList<int> IntList; | 
| 149 | typedef QList<qreal> RealList; | 
| 150 |  | 
| 151 | void tst_QEasingCurve::valueForProgress_data() | 
| 152 | { | 
| 153 |     QTest::addColumn<int>(name: "type" ); | 
| 154 |     QTest::addColumn<IntList>(name: "at" ); | 
| 155 |     QTest::addColumn<RealList>(name: "expected" ); | 
| 156 |     // automatically generated. | 
| 157 |     // note that values are scaled from range [0,1] to range [0, 100] in order to store them as | 
| 158 |     // integer values and avoid fp inaccuracies | 
| 159 |     QTest::newRow(dataTag: "Linear" ) << int(QEasingCurve::Linear) | 
| 160 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 161 |          << (RealList() << 0.0000 << 0.1000 << 0.2000 << 0.3000 << 0.4000 << 0.5000 << 0.6000 << 0.7000 << 0.8000 << 0.9000 << 1.0000); | 
| 162 |  | 
| 163 |     QTest::newRow(dataTag: "InQuad" ) << int(QEasingCurve::InQuad) | 
| 164 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 165 |          << (RealList() << 0.0000 << 0.0100 << 0.0400 << 0.0900 << 0.1600 << 0.2500 << 0.3600 << 0.4900 << 0.6400 << 0.8100 << 1.0000); | 
| 166 |  | 
| 167 |     QTest::newRow(dataTag: "OutQuad" ) << int(QEasingCurve::OutQuad) | 
| 168 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 169 |          << (RealList() << 0.0000 << 0.1900 << 0.3600 << 0.5100 << 0.6400 << 0.7500 << 0.8400 << 0.9100 << 0.9600 << 0.9900 << 1.0000); | 
| 170 |  | 
| 171 |     QTest::newRow(dataTag: "InOutQuad" ) << int(QEasingCurve::InOutQuad) | 
| 172 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 173 |          << (RealList() << 0.0000 << 0.0200 << 0.0800 << 0.1800 << 0.3200 << 0.5000 << 0.6800 << 0.8200 << 0.9200 << 0.9800 << 1.0000); | 
| 174 |  | 
| 175 |     QTest::newRow(dataTag: "OutInQuad" ) << int(QEasingCurve::OutInQuad) | 
| 176 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 177 |          << (RealList() << 0.0000 << 0.1800 << 0.3200 << 0.4200 << 0.4800 << 0.5000 << 0.5200 << 0.5800 << 0.6800 << 0.8200 << 1.0000); | 
| 178 |  | 
| 179 |     QTest::newRow(dataTag: "InCubic" ) << int(QEasingCurve::InCubic) | 
| 180 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 181 |          << (RealList() << 0.0000 << 0.0010 << 0.0080 << 0.0270 << 0.0640 << 0.1250 << 0.2160 << 0.3430 << 0.5120 << 0.7290 << 1.0000); | 
| 182 |  | 
| 183 |     QTest::newRow(dataTag: "OutCubic" ) << int(QEasingCurve::OutCubic) | 
| 184 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 185 |          << (RealList() << 0.0000 << 0.2710 << 0.4880 << 0.6570 << 0.7840 << 0.8750 << 0.9360 << 0.9730 << 0.9920 << 0.9990 << 1.0000); | 
| 186 |  | 
| 187 |     QTest::newRow(dataTag: "InOutCubic" ) << int(QEasingCurve::InOutCubic) | 
| 188 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 189 |          << (RealList() << 0.0000 << 0.0040 << 0.0320 << 0.1080 << 0.2560 << 0.5000 << 0.7440 << 0.8920 << 0.9680 << 0.9960 << 1.0000); | 
| 190 |  | 
| 191 |     QTest::newRow(dataTag: "OutInCubic" ) << int(QEasingCurve::OutInCubic) | 
| 192 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 193 |          << (RealList() << 0.0000 << 0.2440 << 0.3920 << 0.4680 << 0.4960 << 0.5000 << 0.5040 << 0.5320 << 0.6080 << 0.7560 << 1.0000); | 
| 194 |  | 
| 195 |     QTest::newRow(dataTag: "InQuart" ) << int(QEasingCurve::InQuart) | 
| 196 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 197 |          << (RealList() << 0.0000 << 0.0001 << 0.0016 << 0.0081 << 0.0256 << 0.0625 << 0.1296 << 0.2401 << 0.4096 << 0.6561 << 1.0000); | 
| 198 |  | 
| 199 |     QTest::newRow(dataTag: "OutQuart" ) << int(QEasingCurve::OutQuart) | 
| 200 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 201 |          << (RealList() << 0.0000 << 0.3439 << 0.5904 << 0.7599 << 0.8704 << 0.9375 << 0.9744 << 0.9919 << 0.9984 << 0.9999 << 1.0000); | 
| 202 |  | 
| 203 |     QTest::newRow(dataTag: "InOutQuart" ) << int(QEasingCurve::InOutQuart) | 
| 204 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 205 |          << (RealList() << 0.0000 << 0.0008 << 0.0128 << 0.0648 << 0.2048 << 0.5000 << 0.7952 << 0.9352 << 0.9872 << 0.9992 << 1.0000); | 
| 206 |  | 
| 207 |     QTest::newRow(dataTag: "OutInQuart" ) << int(QEasingCurve::OutInQuart) | 
| 208 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 209 |          << (RealList() << 0.0000 << 0.2952 << 0.4352 << 0.4872 << 0.4992 << 0.5000 << 0.5008 << 0.5128 << 0.5648 << 0.7048 << 1.0000); | 
| 210 |  | 
| 211 |     QTest::newRow(dataTag: "InQuint" ) << int(QEasingCurve::InQuint) | 
| 212 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 213 |          << (RealList() << 0.0000 << 0.0000 << 0.0003 << 0.0024 << 0.0102 << 0.0313 << 0.0778 << 0.1681 << 0.3277 << 0.5905 << 1.0000); | 
| 214 |  | 
| 215 |     QTest::newRow(dataTag: "OutQuint" ) << int(QEasingCurve::OutQuint) | 
| 216 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 217 |          << (RealList() << 0.0000 << 0.4095 << 0.6723 << 0.8319 << 0.9222 << 0.9688 << 0.9898 << 0.9976 << 0.9997 << 1.0000 << 1.0000); | 
| 218 |  | 
| 219 |     QTest::newRow(dataTag: "InOutQuint" ) << int(QEasingCurve::InOutQuint) | 
| 220 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 221 |          << (RealList() << 0.0000 << 0.0002 << 0.0051 << 0.0389 << 0.1638 << 0.5000 << 0.8362 << 0.9611 << 0.9949 << 0.9998 << 1.0000); | 
| 222 |  | 
| 223 |     QTest::newRow(dataTag: "OutInQuint" ) << int(QEasingCurve::OutInQuint) | 
| 224 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 225 |          << (RealList() << 0.0000 << 0.3362 << 0.4611 << 0.4949 << 0.4998 << 0.5000 << 0.5002 << 0.5051 << 0.5389 << 0.6638 << 1.0000); | 
| 226 |  | 
| 227 |     QTest::newRow(dataTag: "InSine" ) << int(QEasingCurve::InSine) | 
| 228 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 229 |          << (RealList() << 0.0000 << 0.0123 << 0.0489 << 0.1090 << 0.1910 << 0.2929 << 0.4122 << 0.5460 << 0.6910 << 0.8436 << 1.0000); | 
| 230 |  | 
| 231 |     QTest::newRow(dataTag: "OutSine" ) << int(QEasingCurve::OutSine) | 
| 232 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 233 |          << (RealList() << 0.0000 << 0.1564 << 0.3090 << 0.4540 << 0.5878 << 0.7071 << 0.8090 << 0.8910 << 0.9511 << 0.9877 << 1.0000); | 
| 234 |  | 
| 235 |     QTest::newRow(dataTag: "InOutSine" ) << int(QEasingCurve::InOutSine) | 
| 236 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 237 |          << (RealList() << 0.0000 << 0.0245 << 0.0955 << 0.2061 << 0.3455 << 0.5000 << 0.6545 << 0.7939 << 0.9045 << 0.9755 << 1.0000); | 
| 238 |  | 
| 239 |     QTest::newRow(dataTag: "OutInSine" ) << int(QEasingCurve::OutInSine) | 
| 240 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 241 |          << (RealList() << 0.0000 << 0.1545 << 0.2939 << 0.4045 << 0.4755 << 0.5000 << 0.5245 << 0.5955 << 0.7061 << 0.8455 << 1.0000); | 
| 242 |  | 
| 243 |     QTest::newRow(dataTag: "InExpo" ) << int(QEasingCurve::InExpo) | 
| 244 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 245 |          << (RealList() << 0.0000 << 0.0010 << 0.0029 << 0.0068 << 0.0146 << 0.0303 << 0.0615 << 0.1240 << 0.2490 << 0.4990 << 1.0000); | 
| 246 |  | 
| 247 |     QTest::newRow(dataTag: "OutExpo" ) << int(QEasingCurve::OutExpo) | 
| 248 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 249 |          << (RealList() << 0.0000 << 0.5005 << 0.7507 << 0.8759 << 0.9384 << 0.9697 << 0.9854 << 0.9932 << 0.9971 << 0.9990 << 1.0000); | 
| 250 |  | 
| 251 |     QTest::newRow(dataTag: "InOutExpo" ) << int(QEasingCurve::InOutExpo) | 
| 252 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 253 |          << (RealList() << 0.0000 << 0.0015 << 0.0073 << 0.0308 << 0.1245 << 0.5003 << 0.8754 << 0.9692 << 0.9927 << 0.9985 << 1.0000); | 
| 254 |  | 
| 255 |     QTest::newRow(dataTag: "OutInExpo" ) << int(QEasingCurve::OutInExpo) | 
| 256 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 257 |          << (RealList() << 0.0000 << 0.3754 << 0.4692 << 0.4927 << 0.4985 << 0.5000 << 0.5015 << 0.5073 << 0.5308 << 0.6245 << 1.0000); | 
| 258 |  | 
| 259 |     QTest::newRow(dataTag: "InCirc" ) << int(QEasingCurve::InCirc) | 
| 260 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 261 |          << (RealList() << 0.0000 << 0.0050 << 0.0202 << 0.0461 << 0.0835 << 0.1340 << 0.2000 << 0.2859 << 0.4000 << 0.5641 << 1.0000); | 
| 262 |  | 
| 263 |     QTest::newRow(dataTag: "OutCirc" ) << int(QEasingCurve::OutCirc) | 
| 264 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 265 |          << (RealList() << 0.0000 << 0.4359 << 0.6000 << 0.7141 << 0.8000 << 0.8660 << 0.9165 << 0.9539 << 0.9798 << 0.9950 << 1.0000); | 
| 266 |  | 
| 267 |     QTest::newRow(dataTag: "InOutCirc" ) << int(QEasingCurve::InOutCirc) | 
| 268 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 269 |          << (RealList() << 0.0000 << 0.0101 << 0.0417 << 0.1000 << 0.2000 << 0.5000 << 0.8000 << 0.9000 << 0.9583 << 0.9899 << 1.0000); | 
| 270 |  | 
| 271 |     QTest::newRow(dataTag: "OutInCirc" ) << int(QEasingCurve::OutInCirc) | 
| 272 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 273 |          << (RealList() << 0.0000 << 0.3000 << 0.4000 << 0.4583 << 0.4899 << 0.5000 << 0.5101 << 0.5417 << 0.6000 << 0.7000 << 1.0000); | 
| 274 |  | 
| 275 |     QTest::newRow(dataTag: "InElastic" ) << int(QEasingCurve::InElastic) | 
| 276 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 277 |          << (RealList() << 0.0000 << 0.0020 << -0.0020 << -0.0039 << 0.0156 << -0.0156 << -0.0313 << 0.1250 << -0.1250 << -0.2500 << 1.0000); | 
| 278 |  | 
| 279 |     QTest::newRow(dataTag: "OutElastic" ) << int(QEasingCurve::OutElastic) | 
| 280 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 281 |          << (RealList() << 0.0000 << 1.2500 << 1.1250 << 0.8750 << 1.0313 << 1.0156 << 0.9844 << 1.0039 << 1.0020 << 0.9980 << 1.0000); | 
| 282 |  | 
| 283 |     QTest::newRow(dataTag: "InOutElastic" ) << int(QEasingCurve::InOutElastic) | 
| 284 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 285 |          << (RealList() << 0.0000 << -0.0010 << 0.0078 << -0.0156 << -0.0625 << 0.5000 << 1.0625 << 1.0156 << 0.9922 << 1.0010 << 1.0000); | 
| 286 |  | 
| 287 |     QTest::newRow(dataTag: "OutInElastic" ) << int(QEasingCurve::OutInElastic) | 
| 288 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 289 |          << (RealList() << 0.0000 << 0.3750 << 0.5625 << 0.4922 << 0.4980 << 0.5000 << 0.4961 << 0.5078 << 0.5313 << 0.2500 << 1.0000); | 
| 290 |  | 
| 291 |     QTest::newRow(dataTag: "InBack" ) << int(QEasingCurve::InBack) | 
| 292 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 293 |          << (RealList() << 0.0000 << -0.0143 << -0.0465 << -0.0802 << -0.0994 << -0.0877 << -0.0290 << 0.0929 << 0.2942 << 0.5912 << 1.0000); | 
| 294 |  | 
| 295 |     QTest::newRow(dataTag: "OutBack" ) << int(QEasingCurve::OutBack) | 
| 296 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 297 |          << (RealList() << 0.0000 << 0.4088 << 0.7058 << 0.9071 << 1.0290 << 1.0877 << 1.0994 << 1.0802 << 1.0465 << 1.0143 << 1.0000); | 
| 298 |  | 
| 299 |     QTest::newRow(dataTag: "InOutBack" ) << int(QEasingCurve::InOutBack) | 
| 300 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 301 |          << (RealList() << 0.0000 << -0.0375 << -0.0926 << -0.0788 << 0.0899 << 0.5000 << 0.9101 << 1.0788 << 1.0926 << 1.0375 << 1.0000); | 
| 302 |  | 
| 303 |     QTest::newRow(dataTag: "OutInBack" ) << int(QEasingCurve::OutInBack) | 
| 304 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 305 |          << (RealList() << 0.0000 << 0.3529 << 0.5145 << 0.5497 << 0.5232 << 0.5000 << 0.4768 << 0.4503 << 0.4855 << 0.6471 << 1.0000); | 
| 306 |  | 
| 307 |     QTest::newRow(dataTag: "InBounce" ) << int(QEasingCurve::InBounce) | 
| 308 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 309 |          << (RealList() << 0.0000 << 0.0119 << 0.0600 << 0.0694 << 0.2275 << 0.2344 << 0.0900 << 0.3194 << 0.6975 << 0.9244 << 1.0000); | 
| 310 |  | 
| 311 |     QTest::newRow(dataTag: "OutBounce" ) << int(QEasingCurve::OutBounce) | 
| 312 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 313 |          << (RealList() << 0.0000 << 0.0756 << 0.3025 << 0.6806 << 0.9100 << 0.7656 << 0.7725 << 0.9306 << 0.9400 << 0.9881 << 1.0000); | 
| 314 |  | 
| 315 |     QTest::newRow(dataTag: "InOutBounce" ) << int(QEasingCurve::InOutBounce) | 
| 316 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 317 |          << (RealList() << 0.0000 << 0.0300 << 0.1138 << 0.0450 << 0.3488 << 0.5000 << 0.6512 << 0.9550 << 0.8863 << 0.9700 << 1.0000); | 
| 318 |  | 
| 319 |     QTest::newRow(dataTag: "OutInBounce" ) << int(QEasingCurve::OutInBounce) | 
| 320 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 321 |          << (RealList() << 0.0000 << 0.1513 << 0.4100 << 0.2725 << 0.4400 << 0.5000 << 0.5600 << 0.7275 << 0.5900 << 0.8488 << 1.0000); | 
| 322 |  | 
| 323 |     QTest::newRow(dataTag: "InCurve" ) << int(QEasingCurve::InCurve) | 
| 324 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 325 |          << (RealList() << 0.0000 << 0.0245 << 0.1059 << 0.2343 << 0.3727 << 0.5000 << 0.6055 << 0.7000 << 0.8000 << 0.9000 << 1.0000); | 
| 326 |  | 
| 327 |     QTest::newRow(dataTag: "OutCurve" ) << int(QEasingCurve::OutCurve) | 
| 328 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 329 |          << (RealList() << 0.0000 << 0.1000 << 0.2000 << 0.3000 << 0.3945 << 0.5000 << 0.6273 << 0.7657 << 0.8941 << 0.9755 << 1.0000); | 
| 330 |  | 
| 331 |     QTest::newRow(dataTag: "SineCurve" ) << int(QEasingCurve::SineCurve) | 
| 332 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 333 |          << (RealList() << 0.0000 << 0.0955 << 0.3455 << 0.6545 << 0.9045 << 1.0000 << 0.9045 << 0.6545 << 0.3455 << 0.0955 << 0.0000); | 
| 334 |  | 
| 335 |     QTest::newRow(dataTag: "CosineCurve" ) << int(QEasingCurve::CosineCurve) | 
| 336 |          << (IntList()  << 0 << 10 << 20 << 30 << 40 << 50 << 60 << 70 << 80 << 90 << 100) | 
| 337 |          << (RealList() << 0.5000 << 0.7939 << 0.9755 << 0.9755 << 0.7939 << 0.5000 << 0.2061 << 0.0245 << 0.0245 << 0.2061 << 0.5000); | 
| 338 |  | 
| 339 | } | 
| 340 |  | 
| 341 | /* | 
| 342 |   "fixedpoint" number that is scaled up by 10000. | 
| 343 |   This is to work around two bugs (precision and rounding error) in QString::setNum(). | 
| 344 |   It does not trim off trailing zeros. This is good, just to emphasize the precision. | 
| 345 | */ | 
| 346 | QString fixedToString(int value) | 
| 347 | { | 
| 348 |     QString str; | 
| 349 |     if (value < 0) { | 
| 350 |         str+= QLatin1Char('-'); | 
| 351 |         value = -value; | 
| 352 |     } | 
| 353 |  | 
| 354 |     QString digitArg(QLatin1String("%1." )); | 
| 355 |     for (int i = 10000; i >= 1; i/=10) { | 
| 356 |         int digit = value/i; | 
| 357 |         value -= digit*i; | 
| 358 |         str.append(s: digitArg.arg(a: digit)); | 
| 359 |         digitArg = QLatin1String("%1" ); | 
| 360 |     } | 
| 361 |     return str; | 
| 362 | } | 
| 363 |  | 
| 364 | void tst_QEasingCurve::valueForProgress() | 
| 365 | { | 
| 366 | #if 0 | 
| 367 |     // used to generate data tables... | 
| 368 |     QFile out; | 
| 369 |     out.open(stdout, QIODevice::WriteOnly); | 
| 370 |     for (int c = QEasingCurve::Linear; c < QEasingCurve::NCurveTypes - 1; ++c) { | 
| 371 |         QEasingCurve curve((QEasingCurve::Type)c); | 
| 372 |         QMetaObject mo = QEasingCurve::staticMetaObject; | 
| 373 |         QString strCurve = QLatin1String(mo.enumerator(mo.indexOfEnumerator("Type" )).key(c)); | 
| 374 |         QString strInputs; | 
| 375 |         QString strOutputs; | 
| 376 |  | 
| 377 |         for (int t = 0; t <= 100; t+= 10) { | 
| 378 |             qreal ease = curve.valueForProgress(t/qreal(100)); | 
| 379 |             strInputs += QString::fromLatin1(" << %1" ).arg(t); | 
| 380 |             strOutputs += " << "  + fixedToString(qRound(ease*10000)); | 
| 381 |         } | 
| 382 |         QString str = QString::fromLatin1("    QTest::newRow(\"%1\") << int(QEasingCurve::%2)\n"  | 
| 383 |                                                 "         << (IntList() %3)\n"  | 
| 384 |                                                 "         << (RealList()%4);\n\n" ) | 
| 385 |                                       .arg(strCurve) | 
| 386 |                                       .arg(strCurve) | 
| 387 |                                       .arg(strInputs) | 
| 388 |                                       .arg(strOutputs); | 
| 389 |         out.write(str.toLatin1().constData()); | 
| 390 |     } | 
| 391 |     out.close(); | 
| 392 |     exit(1); | 
| 393 | #else | 
| 394 |     QFETCH(int, type); | 
| 395 |     QFETCH(IntList, at); | 
| 396 |     QFETCH(RealList, expected); | 
| 397 |  | 
| 398 |     QEasingCurve curve((QEasingCurve::Type)type); | 
| 399 |     // in theory the baseline should't have an error of more than 0.00005 due to how its rounded, | 
| 400 |     // but due to FP imprecision, we have to adjust the error a bit more. | 
| 401 |     const qreal errorBound = 0.00006; | 
| 402 |     for (int i = 0; i < at.count(); ++i) { | 
| 403 |         const qreal ex = expected.at(i); | 
| 404 |         const qreal error = qAbs(t: ex - curve.valueForProgress(progress: at.at(i)/qreal(100))); | 
| 405 |         QVERIFY(error <= errorBound); | 
| 406 |     } | 
| 407 |  | 
| 408 |     if (type != QEasingCurve::SineCurve && type != QEasingCurve::CosineCurve) { | 
| 409 |         QVERIFY( !(curve.valueForProgress(0) > 0) ); | 
| 410 |         QVERIFY( !(curve.valueForProgress(1) < 1) ); | 
| 411 |     } | 
| 412 | #endif | 
| 413 | } | 
| 414 |  | 
| 415 | static qreal discreteEase(qreal progress) | 
| 416 | { | 
| 417 |     return qFloor(v: progress * 10) / qreal(10.0); | 
| 418 | } | 
| 419 |  | 
| 420 | void tst_QEasingCurve::setCustomType() | 
| 421 | { | 
| 422 |     QEasingCurve curve; | 
| 423 |     curve.setCustomType(&discreteEase); | 
| 424 |     QCOMPARE(curve.type(), QEasingCurve::Custom); | 
| 425 |     QCOMPARE(curve.valueForProgress(0.0), 0.0); | 
| 426 |     QCOMPARE(curve.valueForProgress(0.05), 0.0); | 
| 427 |     QCOMPARE(curve.valueForProgress(0.10), 0.1); | 
| 428 |     QCOMPARE(curve.valueForProgress(0.15), 0.1); | 
| 429 |     QCOMPARE(curve.valueForProgress(0.20), 0.2); | 
| 430 |     QCOMPARE(curve.valueForProgress(0.25), 0.2); | 
| 431 |     // QTBUG-69947, MinGW 7.3, 8.1 x86 returns 0.2 | 
| 432 | #if defined(Q_CC_MINGW) | 
| 433 | #if !defined(__GNUC__) || defined(__MINGW64__) | 
| 434 |     QCOMPARE(curve.valueForProgress(0.30), 0.3); | 
| 435 | #endif | 
| 436 | #endif | 
| 437 |     QCOMPARE(curve.valueForProgress(0.35), 0.3); | 
| 438 |     QCOMPARE(curve.valueForProgress(0.999999), 0.9); | 
| 439 |  | 
| 440 |     curve.setType(QEasingCurve::Linear); | 
| 441 |     QCOMPARE(curve.type(), QEasingCurve::Linear); | 
| 442 |     QCOMPARE(curve.valueForProgress(0.0), 0.0); | 
| 443 |     QCOMPARE(curve.valueForProgress(0.1), 0.1); | 
| 444 |     QCOMPARE(curve.valueForProgress(0.5), 0.5); | 
| 445 |     QCOMPARE(curve.valueForProgress(0.99), 0.99); | 
| 446 | } | 
| 447 |  | 
| 448 | void tst_QEasingCurve::operators() | 
| 449 | { | 
| 450 |     { // member-swap() | 
| 451 |         QEasingCurve ec1, ec2; | 
| 452 |         ec2.setCustomType(&discreteEase); | 
| 453 |         ec1.swap(other&: ec2); | 
| 454 |         QCOMPARE(ec1.type(), QEasingCurve::Custom); | 
| 455 |     } | 
| 456 |  | 
| 457 |     // operator= | 
| 458 |     QEasingCurve curve; | 
| 459 |     QEasingCurve curve2; | 
| 460 |     curve.setCustomType(&discreteEase); | 
| 461 |     curve2 = curve; | 
| 462 |     QCOMPARE(curve2.type(), QEasingCurve::Custom); | 
| 463 |     QCOMPARE(curve2.valueForProgress(0.0), 0.0); | 
| 464 |     QCOMPARE(curve2.valueForProgress(0.05), 0.0); | 
| 465 |     QCOMPARE(curve2.valueForProgress(0.15), 0.1); | 
| 466 |     QCOMPARE(curve2.valueForProgress(0.25), 0.2); | 
| 467 |     QCOMPARE(curve2.valueForProgress(0.35), 0.3); | 
| 468 |     QCOMPARE(curve2.valueForProgress(0.999999), 0.9); | 
| 469 |  | 
| 470 |     // operator== | 
| 471 |     curve.setType(QEasingCurve::InBack); | 
| 472 |     curve2 = curve; | 
| 473 |     curve2.setOvershoot(qreal(1.70158)); | 
| 474 |     QCOMPARE(curve.overshoot(), curve2.overshoot()); | 
| 475 |     QVERIFY(curve2 == curve); | 
| 476 |  | 
| 477 |     curve.setOvershoot(3.0); | 
| 478 |     QVERIFY(curve2 != curve); | 
| 479 |     curve2.setOvershoot(3.0); | 
| 480 |     QVERIFY(curve2 == curve); | 
| 481 |  | 
| 482 |     curve2.setType(QEasingCurve::Linear); | 
| 483 |     QCOMPARE(curve.overshoot(), curve2.overshoot()); | 
| 484 |     QVERIFY(curve2 != curve); | 
| 485 |     curve2.setType(QEasingCurve::InBack); | 
| 486 |     QCOMPARE(curve.overshoot(), curve2.overshoot()); | 
| 487 |     QVERIFY(curve2 == curve); | 
| 488 |  | 
| 489 |     QEasingCurve curve3; | 
| 490 |     QEasingCurve curve4; | 
| 491 |     curve4.setAmplitude(curve4.amplitude()); | 
| 492 |     QEasingCurve curve5; | 
| 493 |     curve5.setAmplitude(0.12345); | 
| 494 |     QVERIFY(curve3 == curve4); // default value and not assigned | 
| 495 |     QVERIFY(curve3 != curve5); // unassinged and other value | 
| 496 |     QVERIFY(curve4 != curve5); | 
| 497 | } | 
| 498 |  | 
| 499 | class tst_QEasingProperties : public QObject | 
| 500 | { | 
| 501 |     Q_OBJECT | 
| 502 |     Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing) | 
| 503 | public: | 
| 504 |     tst_QEasingProperties(QObject *parent = 0) : QObject(parent) {} | 
| 505 |  | 
| 506 |     QEasingCurve easing() const { return e; } | 
| 507 |     void setEasing(const QEasingCurve& value) { e = value; } | 
| 508 |  | 
| 509 | private: | 
| 510 |     QEasingCurve e; | 
| 511 | }; | 
| 512 |  | 
| 513 | // Test getting and setting easing properties via the metaobject system. | 
| 514 | void tst_QEasingCurve::properties() | 
| 515 | { | 
| 516 |     tst_QEasingProperties obj; | 
| 517 |  | 
| 518 |     QEasingCurve inOutBack(QEasingCurve::InOutBack); | 
| 519 |     qreal overshoot = 1.5; | 
| 520 |     inOutBack.setOvershoot(overshoot); | 
| 521 |     qreal amplitude = inOutBack.amplitude(); | 
| 522 |     qreal period = inOutBack.period(); | 
| 523 |  | 
| 524 |     obj.setEasing(inOutBack); | 
| 525 |  | 
| 526 |     QEasingCurve easing = qvariant_cast<QEasingCurve>(v: obj.property(name: "easing" )); | 
| 527 |     QCOMPARE(easing.type(), QEasingCurve::InOutBack); | 
| 528 |     QCOMPARE(easing.overshoot(), overshoot); | 
| 529 |     QCOMPARE(easing.amplitude(), amplitude); | 
| 530 |     QCOMPARE(easing.period(), period); | 
| 531 |  | 
| 532 |     QEasingCurve linear(QEasingCurve::Linear); | 
| 533 |     overshoot = linear.overshoot(); | 
| 534 |     amplitude = linear.amplitude(); | 
| 535 |     period = linear.period(); | 
| 536 |  | 
| 537 |     obj.setProperty(name: "easing" , | 
| 538 |                     value: QVariant::fromValue(value: QEasingCurve(QEasingCurve::Linear))); | 
| 539 |  | 
| 540 |     easing = qvariant_cast<QEasingCurve>(v: obj.property(name: "easing" )); | 
| 541 |     QCOMPARE(easing.type(), QEasingCurve::Linear); | 
| 542 |     QCOMPARE(easing.overshoot(), overshoot); | 
| 543 |     QCOMPARE(easing.amplitude(), amplitude); | 
| 544 |     QCOMPARE(easing.period(), period); | 
| 545 | } | 
| 546 |  | 
| 547 | void tst_QEasingCurve::metaTypes() | 
| 548 | { | 
| 549 |     QVERIFY(QMetaType::type("QEasingCurve" ) == QMetaType::QEasingCurve); | 
| 550 |  | 
| 551 |     QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QEasingCurve)), | 
| 552 |              QByteArray("QEasingCurve" )); | 
| 553 |  | 
| 554 |     QVERIFY(QMetaType::isRegistered(QMetaType::QEasingCurve)); | 
| 555 |  | 
| 556 |     QVERIFY(qMetaTypeId<QEasingCurve>() == QMetaType::QEasingCurve); | 
| 557 | } | 
| 558 |  | 
| 559 | /* | 
| 560 |   Test to ensure that regardless of what order properties are set, they should produce the same | 
| 561 |   behavior. | 
| 562 |  */ | 
| 563 | void tst_QEasingCurve::propertyOrderIsNotImportant() | 
| 564 | { | 
| 565 |  | 
| 566 |     QEasingCurve c1; | 
| 567 |     c1.setPeriod(1); | 
| 568 |     c1.setType(QEasingCurve::OutSine); | 
| 569 |     QVERIFY(c1.valueForProgress(0.75) > 0.9); | 
| 570 |  | 
| 571 |     QEasingCurve c2; | 
| 572 |     c2.setType(QEasingCurve::OutSine); | 
| 573 |     c2.setPeriod(1); | 
| 574 |  | 
| 575 |     QCOMPARE(c1.valueForProgress(0.75), c2.valueForProgress(0.75)); | 
| 576 | } | 
| 577 |  | 
| 578 | void tst_QEasingCurve::bezierSpline_data() | 
| 579 | { | 
| 580 |     QTest::addColumn<QString>(name: "definition" ); | 
| 581 |     QTest::addColumn<IntList>(name: "at" ); | 
| 582 |     QTest::addColumn<RealList>(name: "expected" ); | 
| 583 |  | 
| 584 |     QTest::newRow(dataTag: "EasingCurve" ) << QString::fromLatin1(str: "0.2,0 0.6,0.09 0.7,1.0 0.7,0.97 0.74,0.96 0.74,0.95 0.81,0.97 0.9,0.97 1,1" ) | 
| 585 |          << (IntList()  << 0 << 70 << 74 << 100) | 
| 586 |          << (RealList() << 0.0000 << 1.0000 << 0.9500 << 1.0000); | 
| 587 |  | 
| 588 |     //This curve is likely to be numerical instable | 
| 589 |     QTest::newRow(dataTag: "NastyCurve" ) << QString::fromLatin1(str: "0.2,0.2 0.126667,0.646667 0.2,0.8 0.624,0.984 0.930667,0.946667 1,1" ) | 
| 590 |          << (IntList()  << 0 << 20 << 30 << 50 << 75 << 100) | 
| 591 |          << (RealList() << 0.0000 << 0.8000 << 0.8402 << 0.9029 << 0.9515 << 1.0000); | 
| 592 |  | 
| 593 |     QTest::newRow(dataTag: "ComplexCurve" ) << QString::fromLatin1(str: "0,0.47174849 0.17393079,0.35634291 0.18950309,0.47179766 0.2487779,0.91126755 "  | 
| 594 |                                              "0.27029205,-0.11275513 0.33421971,0.12062718 0.41170105,-0.10157488 0.4140625,0.16796875 "  | 
| 595 |                                              "0.4140625,0.16796875 0.4140625,0.16796875 0.59658877,0.36978503 0.67931151,0.89255893 0.711253,0.44658283 "  | 
| 596 |                                              "0.88203125,0.43671875 0.88203125,0.43671875 0.86087213,0.78786873 0.99609375,0.4921875 1,1" ) | 
| 597 |          << (IntList()  << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100) | 
| 598 |          << (RealList() << 0.0000 << 0.4134 << 0.5367 << 0.1107 << 0.0505 << 0.7299 << 0.3030 << 0.4886 << 1.0000); | 
| 599 | } | 
| 600 |  | 
| 601 | static inline void setupBezierSpline(QEasingCurve *easingCurve, const QString &string) | 
| 602 | { | 
| 603 |     QStringList pointStr = string.split(sep: QLatin1Char(' ')); | 
| 604 |  | 
| 605 |     QVector<QPointF> points; | 
| 606 |     foreach (const QString &str, pointStr) { | 
| 607 |         QStringList coordStr = str.split(sep: QLatin1Char(',')); | 
| 608 |         QPointF point(coordStr.first().toDouble(), coordStr.last().toDouble()); | 
| 609 |         points.append(t: point); | 
| 610 |     } | 
| 611 |  | 
| 612 |     QVERIFY(points.count() % 3 == 0); | 
| 613 |  | 
| 614 |     for (int i = 0; i < points.count() / 3; i++) { | 
| 615 |         QPointF c1 = points.at(i: i * 3); | 
| 616 |         QPointF c2 = points.at(i: i * 3 + 1); | 
| 617 |         QPointF p1 = points.at(i: i * 3 + 2); | 
| 618 |         easingCurve->addCubicBezierSegment(c1, c2, endPoint: p1); | 
| 619 |     } | 
| 620 | } | 
| 621 |  | 
| 622 | void tst_QEasingCurve::bezierSpline() | 
| 623 | { | 
| 624 |     QFETCH(QString, definition); | 
| 625 |     QFETCH(IntList, at); | 
| 626 |     QFETCH(RealList, expected); | 
| 627 |  | 
| 628 |     QEasingCurve bezierEasingCurve(QEasingCurve::BezierSpline); | 
| 629 |     setupBezierSpline(easingCurve: &bezierEasingCurve, string: definition); | 
| 630 |  | 
| 631 |     const qreal errorBound = 0.002; | 
| 632 |     for (int i = 0; i < at.count(); ++i) { | 
| 633 |         const qreal ex = expected.at(i); | 
| 634 |         const qreal value = bezierEasingCurve.valueForProgress(progress: at.at(i)/qreal(100)); | 
| 635 |         const qreal error = qAbs(t: ex - value); | 
| 636 |         if (error > errorBound) | 
| 637 |             QCOMPARE(value, ex); | 
| 638 |         QVERIFY(error <= errorBound); | 
| 639 |     } | 
| 640 |  | 
| 641 |     QVERIFY( !(bezierEasingCurve.valueForProgress(0) > 0) ); | 
| 642 |     QVERIFY( !(bezierEasingCurve.valueForProgress(1) < 1) ); | 
| 643 | } | 
| 644 |  | 
| 645 | void tst_QEasingCurve::tcbSpline_data() | 
| 646 | { | 
| 647 |     QTest::addColumn<QString>(name: "definition" ); | 
| 648 |     QTest::addColumn<IntList>(name: "at" ); | 
| 649 |     QTest::addColumn<RealList>(name: "expected" ); | 
| 650 |  | 
| 651 |     QTest::newRow(dataTag: "NegativeCurved" ) << QString::fromLatin1(str: "0.0,0.0,0,0,0 0.4,0.8,0.0,1,0.0 1.0,1.0,0.0,0.0,0" ) | 
| 652 |          << (IntList()  << 0 << 66 << 73 << 100) | 
| 653 |          << (RealList() << 0.0000 << 0.9736 << 0.9774 << 1.0000); | 
| 654 |  | 
| 655 |     //This curve is likely to be numerical instable | 
| 656 |     QTest::newRow(dataTag: "Corner" ) << QString::fromLatin1(str: "0.0,0.0,0,0,0 0.4,0.8,0.0,-1,0.0 1.0,1.0,0.0,0.0,0" ) | 
| 657 |          << (IntList()  << 0 << 20 << 30 << 50 << 75 << 100) | 
| 658 |          << (RealList() << 0.0000 << 0.3999 << 0.5996 << 0.8334 << 0.9166 << 1.0000); | 
| 659 |  | 
| 660 |     QTest::newRow(dataTag: "RoundCurve" ) << QString::fromLatin1(str: "0.0,0.0,0,0,0 0.4,0.8,0.0,0,0.0 1.0,1.0,0.0,0.0,0" ) | 
| 661 |          << (IntList()  << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100) | 
| 662 |          << (RealList() << 0.0000 << 0.3478 << 0.4663 << 0.6664 << 0.8000 << 0.9399 << 0.8746 << 0.9567 << 1.0000); | 
| 663 |  | 
| 664 |     QTest::newRow(dataTag: "Bias" ) << QString::fromLatin1(str: "0.0,0.0,0,0,0 0.4,0.8,0.1,0,1.0 1.0,1.0,0.0,0.0,0" ) | 
| 665 |          << (IntList()  << 0 << 15 << 20 << 30 << 40 << 70 << 50 << 80 << 100) | 
| 666 |          << (RealList() << 0.0000 << 0.2999 << 0.3998 << 0.5997 << 0.8000 << 0.9676 << 0.9136 << 0.9725 << 1.0000); | 
| 667 | } | 
| 668 |  | 
| 669 | static inline void setupTCBSpline(QEasingCurve *easingCurve, const QString &string) | 
| 670 | { | 
| 671 |     QStringList pointStr = string.split(sep: QLatin1Char(' ')); | 
| 672 |  | 
| 673 |     foreach (const QString &str, pointStr) { | 
| 674 |         QStringList coordStr = str.split(sep: QLatin1Char(',')); | 
| 675 |         Q_ASSERT(coordStr.count() == 5); | 
| 676 |         QPointF point(coordStr.first().toDouble(), coordStr.at(i: 1).toDouble()); | 
| 677 |         qreal t = coordStr.at(i: 2).toDouble(); | 
| 678 |         qreal c = coordStr.at(i: 3).toDouble(); | 
| 679 |         qreal b = coordStr.at(i: 4).toDouble(); | 
| 680 |         easingCurve->addTCBSegment(nextPoint: point, t, c ,b); | 
| 681 |     } | 
| 682 | } | 
| 683 |  | 
| 684 | void tst_QEasingCurve::tcbSpline() | 
| 685 | { | 
| 686 |     QFETCH(QString, definition); | 
| 687 |     QFETCH(IntList, at); | 
| 688 |     QFETCH(RealList, expected); | 
| 689 |  | 
| 690 |     QEasingCurve tcbEasingCurve(QEasingCurve::TCBSpline); | 
| 691 |     setupTCBSpline(easingCurve: &tcbEasingCurve, string: definition); | 
| 692 |  | 
| 693 |     const qreal errorBound = 0.002; | 
| 694 |     for (int i = 0; i < at.count(); ++i) { | 
| 695 |         const qreal ex = expected.at(i); | 
| 696 |         const qreal value = tcbEasingCurve.valueForProgress(progress: at.at(i)/qreal(100)); | 
| 697 |         const qreal error = qAbs(t: ex - value); | 
| 698 |         if (error > errorBound) | 
| 699 |             QCOMPARE(value, ex); | 
| 700 |         QVERIFY(error <= errorBound); | 
| 701 |     } | 
| 702 |  | 
| 703 |     QVERIFY( !(tcbEasingCurve.valueForProgress(0) > 0) ); | 
| 704 |     QVERIFY( !(tcbEasingCurve.valueForProgress(1) < 1) ); | 
| 705 | } | 
| 706 |  | 
| 707 | /*This is single precision code for a cubic root used inside the spline easing curve. | 
| 708 |   This code is tested here explicitly. See: qeasingcurve.cpp */ | 
| 709 |  | 
| 710 | float static inline _fast_cbrt(float x) | 
| 711 | { | 
| 712 |     union { | 
| 713 |         float f; | 
| 714 |         quint32 i; | 
| 715 |     } ux; | 
| 716 |  | 
| 717 |     const unsigned int B1 = 709921077; | 
| 718 |  | 
| 719 |     ux.f = x; | 
| 720 |     ux.i = (ux.i / 3 + B1); | 
| 721 |  | 
| 722 |     return ux.f; | 
| 723 | } | 
| 724 |  | 
| 725 | /*This is double precision code for a cubic root used inside the spline easing curve. | 
| 726 |   This code is tested here explicitly. See: qeasingcurve.cpp */ | 
| 727 |  | 
| 728 | double static inline _fast_cbrt(double d) | 
| 729 | { | 
| 730 |     union { | 
| 731 |         double d; | 
| 732 |         quint32 pt[2]; | 
| 733 |     } ut, ux; | 
| 734 |  | 
| 735 |     const unsigned int B1 = 715094163; | 
| 736 |  | 
| 737 |  | 
| 738 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN | 
| 739 |     const int h0 = 1; | 
| 740 | #else | 
| 741 |     const int h0 = 0; | 
| 742 | #endif | 
| 743 |     ut.d = 0.0; | 
| 744 |     ux.d = d; | 
| 745 |  | 
| 746 |     quint32 hx = ux.pt[h0]; //high word of d | 
| 747 |     ut.pt[h0] = hx/3 + B1; | 
| 748 |  | 
| 749 |     return ut.d; | 
| 750 | } | 
| 751 |  | 
| 752 | void tst_QEasingCurve::testCbrtDouble() | 
| 753 | { | 
| 754 |     const double errorBound = 0.0001; | 
| 755 |  | 
| 756 |     for (int i = 0; i < 100000; i++) { | 
| 757 |         double d = double(i) / 1000.0; | 
| 758 |         double t = _fast_cbrt(d); | 
| 759 |  | 
| 760 |         const double t_cubic = t * t * t; | 
| 761 |         const double f = t_cubic + t_cubic + d; | 
| 762 |         if (f != 0.0) | 
| 763 |             t = t * (t_cubic + d + d) / f; | 
| 764 |  | 
| 765 |         double expected = std::pow(x: d, y: 1.0/3.0); | 
| 766 |  | 
| 767 |         const qreal error = qAbs(t: expected - t); | 
| 768 |  | 
| 769 |         if (!(error < errorBound)) { | 
| 770 |             qWarning() << d; | 
| 771 |             qWarning() << error; | 
| 772 |         } | 
| 773 |  | 
| 774 |         QVERIFY(error < errorBound); | 
| 775 |     } | 
| 776 | } | 
| 777 |  | 
| 778 | void tst_QEasingCurve::testCbrtFloat() | 
| 779 | { | 
| 780 |     const float errorBound = 0.0005f; | 
| 781 |  | 
| 782 |     for (int i = 0; i < 100000; i++) { | 
| 783 |         float f = float(i) / 1000.0f; | 
| 784 |         float t = _fast_cbrt(x: f); | 
| 785 |  | 
| 786 |         const float t_cubic = t * t * t; | 
| 787 |         const float fac = t_cubic + t_cubic + f; | 
| 788 |         if (fac != 0.0f) | 
| 789 |             t = t * (t_cubic + f + f) / fac; | 
| 790 |  | 
| 791 |         float expected = std::pow(x: f, y: float(1.0/3.0)); | 
| 792 |  | 
| 793 |         const qreal error = qAbs(t: expected - t); | 
| 794 |  | 
| 795 |         if (!(error < errorBound)) { | 
| 796 |             qWarning() << f; | 
| 797 |             qWarning() << error; | 
| 798 |         } | 
| 799 |  | 
| 800 |         QVERIFY(error < errorBound); | 
| 801 |     } | 
| 802 | } | 
| 803 |  | 
| 804 | void tst_QEasingCurve::cpp11() | 
| 805 | { | 
| 806 |     { | 
| 807 |     QEasingCurve ec( QEasingCurve::InOutBack ); | 
| 808 |     QEasingCurve copy = std::move(ec); // move ctor | 
| 809 |     QCOMPARE( copy.type(), QEasingCurve::InOutBack ); | 
| 810 |     QVERIFY( *reinterpret_cast<void**>(&ec) == 0 ); | 
| 811 |     } | 
| 812 |     { | 
| 813 |     QEasingCurve ec( QEasingCurve::InOutBack ); | 
| 814 |     QEasingCurve copy; | 
| 815 |     const QEasingCurve::Type type = copy.type(); | 
| 816 |     copy = std::move(ec); // move assignment op | 
| 817 |     QCOMPARE( copy.type(), QEasingCurve::InOutBack ); | 
| 818 |     QCOMPARE( ec.type(), type ); | 
| 819 |     } | 
| 820 | } | 
| 821 |  | 
| 822 | void tst_QEasingCurve::quadraticEquation() { | 
| 823 |     // We find the value for a given time by solving a cubic equation. | 
| 824 |     //     ax^3 + bx^2 + cx + d = 0 | 
| 825 |     // However, the solver also needs to take care of cases where a = 0, | 
| 826 |     // b = 0 or c = 0, and the equation becomes quadratic, linear or invalid. | 
| 827 |     // A naive cubic solver might divide by zero and return nan, even | 
| 828 |     // when the solution is a real number. | 
| 829 |     // This test should triggers those cases. | 
| 830 |  | 
| 831 |     { | 
| 832 |         // If the control points are spaced 1/3 apart of the distance of the | 
| 833 |         // start- and endpoint, the equation becomes linear. | 
| 834 |         QEasingCurve test(QEasingCurve::BezierSpline); | 
| 835 |         const qreal p1 = 1.0 / 3.0; | 
| 836 |         const qreal p2 = 1.0 - 1.0 / 3.0; | 
| 837 |         const qreal p3 = 1.0; | 
| 838 |  | 
| 839 |         test.addCubicBezierSegment(c1: QPointF(p1, 0.0), c2: QPointF(p2, 1.0), endPoint: QPointF(p3, 1.0)); | 
| 840 |         QVERIFY(qAbs(test.valueForProgress(0.25) - 0.15625) < 1e-6); | 
| 841 |         QVERIFY(qAbs(test.valueForProgress(0.5) - 0.5) < 1e-6); | 
| 842 |         QVERIFY(qAbs(test.valueForProgress(0.75) - 0.84375) < 1e-6); | 
| 843 |     } | 
| 844 |  | 
| 845 |     { | 
| 846 |         // If both the start point and the first control point | 
| 847 |         // are placed a 0.0, and the second control point is | 
| 848 |         // placed at 1/3, we get a case where a = 0 and b != 0 | 
| 849 |         // i.e. a quadratic equation. | 
| 850 |         QEasingCurve test(QEasingCurve::BezierSpline); | 
| 851 |         const qreal p1 = 0.0; | 
| 852 |         const qreal p2 = 1.0 / 3.0; | 
| 853 |         const qreal p3 = 1.0; | 
| 854 |         test.addCubicBezierSegment(c1: QPointF(p1, 0.0), c2: QPointF(p2, 1.0), endPoint: QPointF(p3, 1.0)); | 
| 855 |         QVERIFY(qAbs(test.valueForProgress(0.25) - 0.5) < 1e-6); | 
| 856 |         QVERIFY(qAbs(test.valueForProgress(0.5) - 0.792893) < 1e-6); | 
| 857 |         QVERIFY(qAbs(test.valueForProgress(0.75) - 0.950962) < 1e-6); | 
| 858 |     } | 
| 859 |  | 
| 860 |     { | 
| 861 |         // If both the start point and the first control point | 
| 862 |         // are placed a 0.0, and the second control point is | 
| 863 |         // placed close to 1/3, we get a case where a = ~0 and b != 0. | 
| 864 |         // It's not truly a quadratic equation, but should be treated | 
| 865 |         // as one, because it causes some cubic solvers to fail. | 
| 866 |         QEasingCurve test(QEasingCurve::BezierSpline); | 
| 867 |         const qreal p1 = 0.0; | 
| 868 |         const qreal p2 = 1.0 / 3.0 + 1e-6; | 
| 869 |         const qreal p3 = 1.0; | 
| 870 |         test.addCubicBezierSegment(c1: QPointF(p1, 0.0), c2: QPointF(p2, 1.0), endPoint: QPointF(p3, 1.0)); | 
| 871 |         QVERIFY(qAbs(test.valueForProgress(0.25) - 0.499999) < 1e-6); | 
| 872 |         QVERIFY(qAbs(test.valueForProgress(0.5) - 0.792892) < 1e-6); | 
| 873 |         QVERIFY(qAbs(test.valueForProgress(0.75) - 0.950961) < 1e-6); | 
| 874 |     } | 
| 875 |  | 
| 876 |     { | 
| 877 |         // A bad case, where the segment is of zero length. | 
| 878 |         // However, it might still happen in user code, | 
| 879 |         // and we should return a sensible answer. | 
| 880 |         QEasingCurve test(QEasingCurve::BezierSpline); | 
| 881 |         const qreal p0 = 0.0; | 
| 882 |         const qreal p1 = p0; | 
| 883 |         const qreal p2 = p0; | 
| 884 |         const qreal p3 = p0; | 
| 885 |         test.addCubicBezierSegment(c1: QPointF(p1, 0.0), c2: QPointF(p2, 1.0), endPoint: QPointF(p3, 1.0)); | 
| 886 |         test.addCubicBezierSegment(c1: QPointF(p3, 1.0), c2: QPointF(1.0, 1.0), endPoint: QPointF(1.0, 1.0)); | 
| 887 |         QCOMPARE(test.valueForProgress(0.0), 0.0); | 
| 888 |     } | 
| 889 | } | 
| 890 |  | 
| 891 | void tst_QEasingCurve::streamInOut_data() | 
| 892 | { | 
| 893 |     QTest::addColumn<int>(name: "version" ); | 
| 894 |     QTest::addColumn<bool>(name: "equality" ); | 
| 895 |  | 
| 896 |     QTest::newRow(dataTag: "5.11" ) << int(QDataStream::Qt_5_11) << false; | 
| 897 |     QTest::newRow(dataTag: "5.13" ) << int(QDataStream::Qt_5_13) << true; | 
| 898 | } | 
| 899 |  | 
| 900 | void tst_QEasingCurve::streamInOut() | 
| 901 | { | 
| 902 |     QFETCH(int, version); | 
| 903 |     QFETCH(bool, equality); | 
| 904 |  | 
| 905 |     QEasingCurve orig; | 
| 906 |     orig.addCubicBezierSegment(c1: QPointF(0.43, 0.0025), c2: QPointF(0.38, 0.51), endPoint: QPointF(0.57, 0.99)); | 
| 907 |  | 
| 908 |     QEasingCurve copy; | 
| 909 |  | 
| 910 |     QByteArray data; | 
| 911 |     QDataStream dsw(&data,QIODevice::WriteOnly); | 
| 912 |     QDataStream dsr(&data,QIODevice::ReadOnly); | 
| 913 |  | 
| 914 |     dsw.setVersion(version); | 
| 915 |     dsr.setVersion(version); | 
| 916 |     dsw << orig; | 
| 917 |     dsr >> copy; | 
| 918 |  | 
| 919 |     QCOMPARE(copy == orig, equality); | 
| 920 | } | 
| 921 |  | 
| 922 | QTEST_MAIN(tst_QEasingCurve) | 
| 923 | #include "tst_qeasingcurve.moc" | 
| 924 |  |