File indexing completed on 2024-10-20 04:17:38
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 "colorwheel.h" 0007 // Second, the private implementation. 0008 #include "colorwheel_p.h" // IWYU pragma: keep 0009 0010 #include "constpropagatinguniquepointer.h" 0011 #include "helpermath.h" 0012 #include "rgbcolorspace.h" 0013 #include <qapplication.h> 0014 #include <qboxlayout.h> 0015 #include <qglobal.h> 0016 #include <qlineedit.h> 0017 #include <qnamespace.h> 0018 #include <qobject.h> 0019 #include <qpoint.h> 0020 #include <qsharedpointer.h> 0021 #include <qsignalspy.h> 0022 #include <qsize.h> 0023 #include <qtest.h> 0024 #include <qtestcase.h> 0025 #include <qtestkeyboard.h> 0026 #include <qtestmouse.h> 0027 #include <qwidget.h> 0028 0029 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0030 #include <qtmetamacros.h> 0031 #else 0032 #include <qobjectdefs.h> 0033 #include <qstring.h> 0034 #endif 0035 0036 namespace PerceptualColor 0037 { 0038 class TestColorWheel : public QObject 0039 { 0040 Q_OBJECT 0041 0042 public: 0043 explicit TestColorWheel(QObject *parent = nullptr) 0044 : QObject(parent) 0045 { 0046 } 0047 0048 private: 0049 QSharedPointer<PerceptualColor::RgbColorSpace> m_rgbColorSpace = RgbColorSpace::createSrgb(); 0050 0051 private Q_SLOTS: 0052 void initTestCase() 0053 { 0054 // Called before the first test function is executed 0055 } 0056 0057 void cleanupTestCase() 0058 { 0059 // Called after the last test function was executed 0060 } 0061 0062 void init() 0063 { 0064 // Called before each test function is executed 0065 } 0066 0067 void cleanup() 0068 { 0069 // Called after every test function 0070 } 0071 0072 void testConstructorDestructor() 0073 { 0074 ColorWheel temp(m_rgbColorSpace); 0075 } 0076 0077 void testMouseFocusBehaviour() 0078 { 0079 QWidget myWindow; 0080 QHBoxLayout *myLayout = new QHBoxLayout; 0081 QLineEdit *myLineEdit = new QLineEdit; 0082 myLayout->addWidget(myLineEdit); 0083 ColorWheel *myColorWheel = new ColorWheel(m_rgbColorSpace); 0084 myLayout->addWidget(myColorWheel); 0085 myWindow.setLayout(myLayout); 0086 0087 // It is necessary to show the widget and make it active 0088 // to make focus and widget events working within unit tests. 0089 myWindow.show(); 0090 QApplication::setActiveWindow(&myWindow); 0091 0092 myLineEdit->setFocus(); 0093 QCOMPARE(myLineEdit->hasFocus(), true); 0094 QCOMPARE(myColorWheel->hasFocus(), false); 0095 0096 // A click that is not in the wheel should not give focus: 0097 QTest::mouseClick( 0098 // Widget to click 0099 myColorWheel, 0100 // Mouse button to simulate 0101 Qt::MouseButton::LeftButton, 0102 // Modifiers 0103 Qt::KeyboardModifier::NoModifier, 0104 // Position for the mouse click 0105 QPoint(10, 10)); 0106 QCOMPARE(myColorWheel->hasFocus(), false); 0107 // A click in the middle should give focus: 0108 QTest::mouseClick( 0109 // Widget to click 0110 myColorWheel, 0111 // Mouse button to simulate 0112 Qt::MouseButton::LeftButton, 0113 // Modifiers 0114 Qt::KeyboardModifier::NoModifier 0115 // Not specifying a point means: click in the center of the widget. 0116 ); 0117 QCOMPARE(myColorWheel->hasFocus(), true); 0118 } 0119 0120 void testHueProperty() 0121 { 0122 ColorWheel myWheel(m_rgbColorSpace); 0123 QSignalSpy mySpy(&myWheel, &ColorWheel::hueChanged); 0124 qreal referenceHue = 12.345; 0125 0126 // Test if signal is emitted. 0127 myWheel.setHue(referenceHue); 0128 QCOMPARE(mySpy.count(), 1); 0129 QCOMPARE(myWheel.hue(), referenceHue); 0130 0131 // Test that no signal is emitted for old hue. 0132 myWheel.setHue(referenceHue); 0133 QCOMPARE(mySpy.count(), 1); 0134 QCOMPARE(myWheel.hue(), referenceHue); 0135 } 0136 0137 void testMinimumSizeHint() 0138 { 0139 ColorWheel myColorWheel(m_rgbColorSpace); 0140 QVERIFY2(myColorWheel.minimumSizeHint().width() > 0, "minimalSizeHint width is implemented."); 0141 QVERIFY2(myColorWheel.minimumSizeHint().height() > 0, "minimalSizeHint height is implemented."); 0142 // Check that the hint is a square: 0143 QCOMPARE(myColorWheel.minimumSizeHint().width(), myColorWheel.minimumSizeHint().height()); 0144 } 0145 0146 void testSizeHint() 0147 { 0148 ColorWheel myColorWheel(m_rgbColorSpace); 0149 QVERIFY2(myColorWheel.sizeHint().width() > myColorWheel.minimumSizeHint().width(), "sizeHint width is bigger than minimalSizeHint width."); 0150 QVERIFY2(myColorWheel.sizeHint().height() > myColorWheel.minimumSizeHint().height(), "sizeHint height is bigger than minimalSizeHint height."); 0151 // Check that the hint is a square: 0152 QCOMPARE(myColorWheel.minimumSizeHint().width(), myColorWheel.minimumSizeHint().height()); 0153 } 0154 0155 void testBorder() 0156 { 0157 ColorWheel myColorWheel(m_rgbColorSpace); 0158 QVERIFY2(myColorWheel.d_pointer->border() > 0, "border() is a valid value > 0."); 0159 } 0160 0161 void testInnerDiameter() 0162 { 0163 ColorWheel myColorWheel(m_rgbColorSpace); 0164 QVERIFY2(myColorWheel.d_pointer->innerDiameter() > 0, "innerDiameter() is a valid value > 0."); 0165 QVERIFY2(myColorWheel.d_pointer->innerDiameter() < myColorWheel.size().width(), "innerDiameter() is smaller than the widget’s width."); 0166 QVERIFY2(myColorWheel.d_pointer->innerDiameter() < myColorWheel.size().height(), "innerDiameter() is smaller than the widget’s height."); 0167 } 0168 0169 void testVerySmallWidgetSizes() 0170 { 0171 // Also very small widget sizes should not crash the widget. 0172 // This might happen because of divisions by 0, even when the widget 0173 // is bigger than 0 because of borders or offsets. We test this 0174 // here with various small sizes, always forcing in immediate 0175 // re-paint. 0176 ColorWheel myWidget{m_rgbColorSpace}; 0177 myWidget.show(); 0178 myWidget.resize(QSize()); 0179 myWidget.repaint(); 0180 myWidget.resize(QSize(-1, -1)); 0181 myWidget.repaint(); 0182 myWidget.resize(QSize(-1, 0)); 0183 myWidget.repaint(); 0184 myWidget.resize(QSize(0, -1)); 0185 myWidget.repaint(); 0186 myWidget.resize(QSize(0, 1)); 0187 myWidget.repaint(); 0188 myWidget.resize(QSize(1, 0)); 0189 myWidget.repaint(); 0190 myWidget.resize(QSize(1, 1)); 0191 myWidget.repaint(); 0192 myWidget.resize(QSize(2, 2)); 0193 myWidget.repaint(); 0194 myWidget.resize(QSize(3, 3)); 0195 myWidget.repaint(); 0196 myWidget.resize(QSize(4, 4)); 0197 myWidget.repaint(); 0198 myWidget.resize(QSize(5, 5)); 0199 myWidget.repaint(); 0200 myWidget.resize(QSize(6, 6)); 0201 myWidget.repaint(); 0202 myWidget.resize(QSize(7, 7)); 0203 myWidget.repaint(); 0204 myWidget.resize(QSize(8, 8)); 0205 myWidget.repaint(); 0206 myWidget.resize(QSize(9, 9)); 0207 myWidget.repaint(); 0208 myWidget.resize(QSize(10, 10)); 0209 myWidget.repaint(); 0210 myWidget.resize(QSize(11, 11)); 0211 myWidget.repaint(); 0212 myWidget.resize(QSize(12, 12)); 0213 myWidget.repaint(); 0214 myWidget.resize(QSize(13, 13)); 0215 myWidget.repaint(); 0216 myWidget.resize(QSize(14, 14)); 0217 myWidget.repaint(); 0218 } 0219 0220 void testOutOfRange() 0221 { 0222 ColorWheel myWidget{m_rgbColorSpace}; 0223 myWidget.show(); 0224 myWidget.resize(QSize(400, 400)); 0225 0226 // Test setting out-of-range hues 0227 0228 const qreal hue = 500; 0229 myWidget.setHue(hue); 0230 // Out-of-range hues should initially be preserved. 0231 QCOMPARE(myWidget.hue(), 500); 0232 // After user interaction, they should be normalized. 0233 QTest::keyClick(&myWidget, Qt::Key_Plus); 0234 QVERIFY(isInRange<qreal>(0, myWidget.hue(), 360)); 0235 } 0236 }; 0237 0238 } // namespace PerceptualColor 0239 0240 QTEST_MAIN(PerceptualColor::TestColorWheel) 0241 0242 // The following “include” is necessary because we do not use a header file: 0243 #include "testcolorwheel.moc"