File indexing completed on 2024-07-14 04:37:05

0001 // SPDX-FileCopyrightText: Lukas Sommer <sommerluk@gmail.com>
0002 // SPDX-License-Identifier: BSD-2-Clause OR MIT
0003 
0004 // First included header is the public header of the class we are testing;
0005 // this forces the header to be self-contained.
0006 #include "gradientslider.h"
0007 // Second, the private implementation.
0008 #include "gradientslider_p.h" // IWYU pragma: keep
0009 
0010 #include "constpropagatinguniquepointer.h"
0011 #include "gradientimageparameters.h"
0012 #include "lchadouble.h"
0013 #include "rgbcolorspacefactory.h"
0014 #include <qglobal.h>
0015 #include <qnamespace.h>
0016 #include <qobject.h>
0017 #include <qpoint.h>
0018 #include <qsharedpointer.h>
0019 #include <qsignalspy.h>
0020 #include <qsize.h>
0021 #include <qsizepolicy.h>
0022 #include <qtest.h>
0023 #include <qtestcase.h>
0024 #include <qtestkeyboard.h>
0025 
0026 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
0027 #include <qtmetamacros.h>
0028 #else
0029 #include <qobjectdefs.h>
0030 #include <qstring.h>
0031 #endif
0032 
0033 namespace PerceptualColor
0034 {
0035 class RgbColorSpace;
0036 
0037 class TestGradientSlider : public QObject
0038 {
0039     Q_OBJECT
0040 
0041 public:
0042     explicit TestGradientSlider(QObject *parent = nullptr)
0043         : QObject(parent)
0044     {
0045     }
0046 
0047 private:
0048     QSharedPointer<PerceptualColor::RgbColorSpace> m_rgbColorSpace = RgbColorSpaceFactory::createSrgb();
0049 
0050 private Q_SLOTS:
0051     void initTestCase()
0052     {
0053         // Called before the first test function is executed
0054     }
0055 
0056     void cleanupTestCase()
0057     {
0058         // Called after the last test function was executed
0059     }
0060 
0061     void init()
0062     {
0063         // Called before each test function is executed
0064     }
0065 
0066     void cleanup()
0067     {
0068         // Called after every test function
0069     }
0070 
0071     void testConstructorAndDestructor()
0072     {
0073         // Constructor and destructor should not crash.
0074         GradientSlider test(m_rgbColorSpace);
0075         QCOMPARE(test.d_pointer->m_gradientImageParameters.rgbColorSpace, //
0076                  m_rgbColorSpace);
0077         QCOMPARE(test.d_pointer->m_orientation, Qt::Vertical);
0078     }
0079 
0080     void testConstructorAndDestructorHorizontal()
0081     {
0082         // Constructor and destructor should not crash.
0083         GradientSlider test(m_rgbColorSpace, Qt::Horizontal);
0084         QCOMPARE(test.d_pointer->m_gradientImageParameters.rgbColorSpace, //
0085                  m_rgbColorSpace);
0086         QCOMPARE(test.d_pointer->m_orientation, Qt::Horizontal);
0087     }
0088 
0089     void testConstructorAndDestructorVertical()
0090     {
0091         // Constructor and destructor should not crash.
0092         GradientSlider test(m_rgbColorSpace, Qt::Vertical);
0093         QCOMPARE(test.d_pointer->m_gradientImageParameters.rgbColorSpace, //
0094                  m_rgbColorSpace);
0095         QCOMPARE(test.d_pointer->m_orientation, Qt::Vertical);
0096     }
0097 
0098     void testFirstColor()
0099     {
0100         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0101         LchaDouble color;
0102         color.l = 50;
0103         color.c = 50;
0104         color.h = 50;
0105         color.a = 1;
0106         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::firstColorChanged);
0107         testSlider.setFirstColor(color);
0108         QVERIFY(testSlider.firstColor().hasSameCoordinates(color));
0109         QCOMPARE(spy.count(), 1);
0110     }
0111 
0112     void testSecondColor()
0113     {
0114         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0115         LchaDouble color;
0116         color.l = 50;
0117         color.c = 50;
0118         color.h = 50;
0119         color.a = 1;
0120         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::secondColorChanged);
0121         testSlider.setSecondColor(color);
0122         QVERIFY(testSlider.secondColor().hasSameCoordinates(color));
0123         QCOMPARE(spy.count(), 1);
0124     }
0125 
0126     void testSetColors()
0127     {
0128         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0129         LchaDouble color;
0130         color.l = 50;
0131         color.c = 50;
0132         color.h = 50;
0133         color.a = 1;
0134         QSignalSpy spyFirst(&testSlider, &PerceptualColor::GradientSlider::firstColorChanged);
0135         QSignalSpy spySecond(&testSlider, &PerceptualColor::GradientSlider::secondColorChanged);
0136         testSlider.setColors(color, color);
0137         QVERIFY(testSlider.firstColor().hasSameCoordinates(color));
0138         QCOMPARE(spyFirst.count(), 1);
0139         QVERIFY(testSlider.secondColor().hasSameCoordinates(color));
0140         QCOMPARE(spySecond.count(), 1);
0141     }
0142 
0143     void testMinimalSizeHint()
0144     {
0145         GradientSlider testWidget(m_rgbColorSpace);
0146         QVERIFY2(testWidget.minimumSizeHint().width() > 0, "minimalSizeHint width is implemented.");
0147         QVERIFY2(testWidget.minimumSizeHint().height() > 0, "minimalSizeHint height is implemented.");
0148     }
0149 
0150     void testSizeHint()
0151     {
0152         GradientSlider testWidget(m_rgbColorSpace);
0153         QVERIFY2(testWidget.sizeHint().width() >= testWidget.minimumSizeHint().width(), "sizeHint width is bigger than or equal to minimalSizeHint width.");
0154         QVERIFY2(testWidget.sizeHint().height() >= testWidget.minimumSizeHint().height(),
0155                  "sizeHint height is bigger than or equal to minimalSizeHint "
0156                  "height.");
0157     }
0158 
0159     void testSingleStep()
0160     {
0161         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0162         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::singleStepChanged);
0163         testSlider.setSingleStep(0.5);
0164         QCOMPARE(spy.count(), 1);
0165         QCOMPARE(testSlider.singleStep(), 0.5);
0166         QCOMPARE(testSlider.d_pointer->m_singleStep, 0.5);
0167         testSlider.setSingleStep(0.2);
0168         QCOMPARE(spy.count(), 2);
0169         QCOMPARE(testSlider.singleStep(), 0.2);
0170         QCOMPARE(testSlider.d_pointer->m_singleStep, 0.2);
0171         testSlider.setSingleStep(-10);
0172         QCOMPARE(spy.count(), 3);
0173         QCOMPARE(testSlider.singleStep(), 0);
0174         QCOMPARE(testSlider.d_pointer->m_singleStep, 0);
0175         testSlider.setSingleStep(10);
0176         QCOMPARE(spy.count(), 4);
0177         QCOMPARE(testSlider.singleStep(), 1);
0178         QCOMPARE(testSlider.d_pointer->m_singleStep, 1);
0179     }
0180 
0181     void testPageStep()
0182     {
0183         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0184         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::pageStepChanged);
0185         testSlider.setPageStep(0.5);
0186         QCOMPARE(spy.count(), 1);
0187         QCOMPARE(testSlider.pageStep(), 0.5);
0188         QCOMPARE(testSlider.d_pointer->m_pageStep, 0.5);
0189         testSlider.setPageStep(0.2);
0190         QCOMPARE(spy.count(), 2);
0191         QCOMPARE(testSlider.pageStep(), 0.2);
0192         QCOMPARE(testSlider.d_pointer->m_pageStep, 0.2);
0193         testSlider.setPageStep(-10);
0194         QCOMPARE(spy.count(), 3);
0195         QCOMPARE(testSlider.pageStep(), 0);
0196         QCOMPARE(testSlider.d_pointer->m_pageStep, 0);
0197         testSlider.setPageStep(10);
0198         QCOMPARE(spy.count(), 4);
0199         QCOMPARE(testSlider.pageStep(), 1);
0200         QCOMPARE(testSlider.d_pointer->m_pageStep, 1);
0201     }
0202 
0203     void testValue()
0204     {
0205         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0206         testSlider.setValue(0.3);
0207         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::valueChanged);
0208         testSlider.setValue(0.5);
0209         QCOMPARE(spy.count(), 1);
0210         QCOMPARE(testSlider.value(), 0.5);
0211         QCOMPARE(testSlider.d_pointer->m_value, 0.5);
0212         testSlider.setValue(0.2);
0213         QCOMPARE(spy.count(), 2);
0214         QCOMPARE(testSlider.value(), 0.2);
0215         QCOMPARE(testSlider.d_pointer->m_value, 0.2);
0216         testSlider.setValue(-10);
0217         QCOMPARE(spy.count(), 3);
0218         QCOMPARE(testSlider.value(), 0);
0219         QCOMPARE(testSlider.d_pointer->m_value, 0);
0220         testSlider.setValue(10);
0221         QCOMPARE(spy.count(), 4);
0222         QCOMPARE(testSlider.value(), 1);
0223         QCOMPARE(testSlider.d_pointer->m_value, 1);
0224     }
0225 
0226     void testKeyPressEventLTR()
0227     {
0228         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0229         testSlider.setLayoutDirection(Qt::LayoutDirection::LeftToRight);
0230         testSlider.setSingleStep(0.1);
0231         testSlider.setPageStep(0.2);
0232         testSlider.setValue(0.3);
0233         QTest::keyClick(&testSlider, Qt::Key_Plus);
0234         QCOMPARE(testSlider.value(), 0.4);
0235         QTest::keyClick(&testSlider, Qt::Key_Minus);
0236         QCOMPARE(testSlider.value(), 0.3);
0237         QTest::keyClick(&testSlider, Qt::Key_Up);
0238         QCOMPARE(testSlider.value(), 0.4);
0239         QTest::keyClick(&testSlider, Qt::Key_Down);
0240         QCOMPARE(testSlider.value(), 0.3);
0241         QTest::keyClick(&testSlider, Qt::Key_Right);
0242         QCOMPARE(testSlider.value(), 0.4);
0243         QTest::keyClick(&testSlider, Qt::Key_Left);
0244         QCOMPARE(testSlider.value(), 0.3);
0245         QTest::keyClick(&testSlider, Qt::Key_PageUp);
0246         QCOMPARE(testSlider.value(), 0.5);
0247         QTest::keyClick(&testSlider, Qt::Key_PageDown);
0248         QCOMPARE(testSlider.value(), 0.3);
0249         QTest::keyClick(&testSlider, Qt::Key_Home);
0250         QCOMPARE(testSlider.value(), 0.0);
0251         QTest::keyClick(&testSlider, Qt::Key_End);
0252         QCOMPARE(testSlider.value(), 1.0);
0253     }
0254 
0255     void testKeyPressEventRTL()
0256     {
0257         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0258         testSlider.setLayoutDirection(Qt::LayoutDirection::RightToLeft);
0259         testSlider.setSingleStep(0.1);
0260         testSlider.setPageStep(0.2);
0261         testSlider.setValue(0.3);
0262         QTest::keyClick(&testSlider, Qt::Key_Plus);
0263         QCOMPARE(testSlider.value(), 0.4);
0264         QTest::keyClick(&testSlider, Qt::Key_Minus);
0265         QCOMPARE(testSlider.value(), 0.3);
0266         QTest::keyClick(&testSlider, Qt::Key_Up);
0267         QCOMPARE(testSlider.value(), 0.4);
0268         QTest::keyClick(&testSlider, Qt::Key_Down);
0269         QCOMPARE(testSlider.value(), 0.3);
0270         QTest::keyClick(&testSlider, Qt::Key_Left);
0271         QCOMPARE(testSlider.value(), 0.4);
0272         QTest::keyClick(&testSlider, Qt::Key_Right);
0273         QCOMPARE(testSlider.value(), 0.3);
0274         QTest::keyClick(&testSlider, Qt::Key_PageUp);
0275         QCOMPARE(testSlider.value(), 0.5);
0276         QTest::keyClick(&testSlider, Qt::Key_PageDown);
0277         QCOMPARE(testSlider.value(), 0.3);
0278         QTest::keyClick(&testSlider, Qt::Key_Home);
0279         QCOMPARE(testSlider.value(), 0.0);
0280         QTest::keyClick(&testSlider, Qt::Key_End);
0281         QCOMPARE(testSlider.value(), 1.0);
0282     }
0283 
0284     void testOrientationDefaultConstructor()
0285     {
0286         GradientSlider testSlider(m_rgbColorSpace);
0287         QCOMPARE(testSlider.orientation(), Qt::Orientation::Vertical);
0288         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
0289         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Expanding);
0290     }
0291 
0292     void testOrientationVerticalConstructor()
0293     {
0294         GradientSlider testSlider(m_rgbColorSpace, Qt::Orientation::Vertical);
0295         QCOMPARE(testSlider.orientation(), Qt::Orientation::Vertical);
0296         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
0297         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Expanding);
0298     }
0299 
0300     void testOrientationHorizontalConstructor()
0301     {
0302         GradientSlider testSlider(m_rgbColorSpace, Qt::Orientation::Horizontal);
0303         QCOMPARE(testSlider.orientation(), Qt::Orientation::Horizontal);
0304         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Expanding);
0305         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Fixed);
0306     }
0307 
0308     void testOrientation()
0309     {
0310         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0311         QCOMPARE(testSlider.orientation(), Qt::Orientation::Vertical);
0312         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::orientationChanged);
0313         testSlider.setOrientation(Qt::Orientation::Horizontal);
0314         QCOMPARE(testSlider.orientation(), Qt::Orientation::Horizontal);
0315         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Expanding);
0316         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Fixed);
0317         QCOMPARE(spy.count(), 1);
0318         testSlider.setOrientation(Qt::Orientation::Vertical);
0319         QCOMPARE(testSlider.orientation(), Qt::Orientation::Vertical);
0320         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Fixed);
0321         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Expanding);
0322         QCOMPARE(spy.count(), 2);
0323     }
0324 
0325     void testSetOrientationWithoutSignalAndForceNewSizePolicy()
0326     {
0327         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0328         QCOMPARE(testSlider.orientation(), Qt::Orientation::Vertical);
0329         QSignalSpy spy(&testSlider, &PerceptualColor::GradientSlider::orientationChanged);
0330         testSlider.d_pointer->setOrientationWithoutSignalAndForceNewSizePolicy(Qt::Orientation::Horizontal);
0331         QCOMPARE(testSlider.orientation(), Qt::Orientation::Horizontal);
0332         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Expanding);
0333         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Fixed);
0334         QCOMPARE(spy.count(), 0);
0335         testSlider.d_pointer->setOrientationWithoutSignalAndForceNewSizePolicy(Qt::Orientation::Horizontal);
0336         QCOMPARE(testSlider.orientation(), Qt::Orientation::Horizontal);
0337         QCOMPARE(testSlider.sizePolicy().horizontalPolicy(), QSizePolicy::Expanding);
0338         QCOMPARE(testSlider.sizePolicy().verticalPolicy(), QSizePolicy::Fixed);
0339         QCOMPARE(spy.count(), 0);
0340     }
0341 
0342     void testPhysicalPixelLength()
0343     {
0344         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0345         QVERIFY2(testSlider.d_pointer->physicalPixelLength() >= 0, "physicalPixelLength() should be ≥ 0.");
0346     }
0347 
0348     void testPhysicalPixelThickness()
0349     {
0350         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0351         QVERIFY2(testSlider.d_pointer->physicalPixelThickness() >= 0, "physicalPixelLength() should be ≥ 0.");
0352     }
0353 
0354     void testFromWidgetPositionToValue()
0355     {
0356         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0357         qreal value;
0358         value = testSlider.d_pointer->fromWidgetPixelPositionToValue(QPoint(0, 0));
0359         QVERIFY2((value >= 0) && (value <= 1), "fromWidgetPixelPositionToValue() should be 0 ≤ value ≤ 1.");
0360         value = testSlider.d_pointer->fromWidgetPixelPositionToValue(QPoint(-100, -100));
0361         QVERIFY2((value >= 0) && (value <= 1), "fromWidgetPixelPositionToValue() should be 0 ≤ value ≤ 1.");
0362         value = testSlider.d_pointer->fromWidgetPixelPositionToValue(QPoint(10000, 10000));
0363         QVERIFY2((value >= 0) && (value <= 1), "fromWidgetPixelPositionToValue() should be 0 ≤ value ≤ 1.");
0364     }
0365 
0366     void testPaintEvent()
0367     {
0368         GradientSlider testSlider(m_rgbColorSpace, Qt::Vertical);
0369         testSlider.show();
0370         // Paint event should not crash.
0371         // repaint() will call paintEvent()…
0372         testSlider.repaint();
0373     }
0374 
0375     void testVerySmallWidgetSizes()
0376     {
0377         // Also very small widget sizes should not crash the widget.
0378         // This might happen because of divisions by 0, even when the widget
0379         // is bigger than 0 because of borders or offsets. We test this
0380         // here with various small sizes, always forcing in immediate
0381         // re-paint.
0382         GradientSlider myWidget{m_rgbColorSpace};
0383         myWidget.show();
0384         myWidget.resize(QSize());
0385         myWidget.repaint();
0386         myWidget.resize(QSize(-1, -1));
0387         myWidget.repaint();
0388         myWidget.resize(QSize(-1, 0));
0389         myWidget.repaint();
0390         myWidget.resize(QSize(0, -1));
0391         myWidget.repaint();
0392         myWidget.resize(QSize(0, 1));
0393         myWidget.repaint();
0394         myWidget.resize(QSize(1, 0));
0395         myWidget.repaint();
0396         myWidget.resize(QSize(1, 1));
0397         myWidget.repaint();
0398         myWidget.resize(QSize(2, 2));
0399         myWidget.repaint();
0400         myWidget.resize(QSize(3, 3));
0401         myWidget.repaint();
0402         myWidget.resize(QSize(4, 4));
0403         myWidget.repaint();
0404         myWidget.resize(QSize(5, 5));
0405         myWidget.repaint();
0406         myWidget.resize(QSize(6, 6));
0407         myWidget.repaint();
0408         myWidget.resize(QSize(7, 7));
0409         myWidget.repaint();
0410         myWidget.resize(QSize(8, 8));
0411         myWidget.repaint();
0412         myWidget.resize(QSize(9, 9));
0413         myWidget.repaint();
0414         myWidget.resize(QSize(10, 10));
0415         myWidget.repaint();
0416         myWidget.resize(QSize(11, 11));
0417         myWidget.repaint();
0418         myWidget.resize(QSize(12, 12));
0419         myWidget.repaint();
0420         myWidget.resize(QSize(13, 13));
0421         myWidget.repaint();
0422         myWidget.resize(QSize(14, 14));
0423         myWidget.repaint();
0424     }
0425 
0426     void testOutOfGamutColors()
0427     {
0428         GradientSlider myWidget{m_rgbColorSpace};
0429         myWidget.show();
0430         myWidget.resize(QSize(100, 100));
0431 
0432         // Test that setting out-of-gamut colors works
0433         const LchaDouble myFirstColor{100, 150, 0, 1};
0434         const LchaDouble mySecondColor{0, 150, 0, 1};
0435         myWidget.setFirstColor(myFirstColor);
0436         myWidget.setSecondColor(mySecondColor);
0437         QVERIFY(myFirstColor.hasSameCoordinates(myWidget.firstColor()));
0438         QVERIFY(myFirstColor.hasSameCoordinates(myWidget.d_pointer->m_firstColor));
0439         QVERIFY(mySecondColor.hasSameCoordinates(myWidget.secondColor()));
0440         QVERIFY(mySecondColor.hasSameCoordinates(myWidget.d_pointer->m_secondColor));
0441     }
0442 
0443     void testOutOfRange()
0444     {
0445         GradientSlider myWidget{m_rgbColorSpace};
0446         myWidget.show();
0447         myWidget.resize(QSize(100, 100));
0448 
0449         // Test that setting colors, that are not only out-of-gamut colors
0450         // but also out of a reasonable range, works.
0451         const LchaDouble myFirstColor{300, 550, -10, 1};
0452         const LchaDouble mySecondColor{-100, -150, 890, 1};
0453         myWidget.setFirstColor(myFirstColor);
0454         myWidget.setSecondColor(mySecondColor);
0455         QVERIFY(myFirstColor.hasSameCoordinates(myWidget.firstColor()));
0456         QVERIFY(myFirstColor.hasSameCoordinates(myWidget.d_pointer->m_firstColor));
0457         QVERIFY(mySecondColor.hasSameCoordinates(myWidget.secondColor()));
0458         QVERIFY(mySecondColor.hasSameCoordinates(myWidget.d_pointer->m_secondColor));
0459     }
0460 };
0461 
0462 } // namespace PerceptualColor
0463 
0464 QTEST_MAIN(PerceptualColor::TestGradientSlider)
0465 
0466 // The following “include” is necessary because we do not use a header file:
0467 #include "testgradientslider.moc"