File indexing completed on 2024-04-14 03:51:11
0001 /* 0002 This file is part of the KDE libraries 0003 SPDX-FileCopyrightText: 2012 Albert Astals Cid <aacid@kde.org> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include <QTest> 0009 #include <QTestEvent> 0010 0011 #include <QComboBox> 0012 #include <QDialogButtonBox> 0013 #include <QLineEdit> 0014 #include <QPushButton> 0015 #include <QSignalSpy> 0016 #include <QSpinBox> 0017 0018 #include <KColorCombo> 0019 #include <KConfigSkeleton> 0020 #include <kconfigdialog.h> 0021 #include <kconfigdialogmanager.h> 0022 0023 #include "signaltest.h" 0024 0025 static const auto CONFIG_FILE = QStringLiteral("kconfigdialog_unittestrc"); 0026 0027 class TextEditUserPropertyWidget : public QWidget 0028 { 0029 Q_OBJECT 0030 // with USER parameter 0031 Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged USER true) 0032 public: 0033 TextEditUserPropertyWidget(QWidget *parent = nullptr) 0034 : QWidget(parent) 0035 { 0036 } 0037 void setText(const QString &text) 0038 { 0039 m_text = text; 0040 Q_EMIT textChanged(m_text); 0041 } 0042 QString text() const 0043 { 0044 return m_text; 0045 } 0046 Q_SIGNALS: 0047 void textChanged(const QString &text); 0048 0049 private: 0050 QString m_text; 0051 }; 0052 0053 class TextEditNoUserPropertyWidget : public QWidget 0054 { 0055 Q_OBJECT 0056 Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) 0057 Q_PROPERTY(QString other READ other WRITE setOther NOTIFY otherChanged USER true) 0058 public: 0059 TextEditNoUserPropertyWidget(QWidget *parent = nullptr) 0060 : QWidget(parent) 0061 { 0062 } 0063 void setText(const QString &text) 0064 { 0065 m_text = text; 0066 Q_EMIT textChanged(m_text); 0067 } 0068 QString text() const 0069 { 0070 return m_text; 0071 } 0072 void setOther(const QString &other) 0073 { 0074 m_other = other; 0075 Q_EMIT textChanged(m_other); 0076 } 0077 QString other() const 0078 { 0079 return m_other; 0080 } 0081 Q_SIGNALS: 0082 void textChanged(const QString &text); 0083 void otherChanged(const QString &other); 0084 0085 private: 0086 QString m_text; 0087 QString m_other; 0088 }; 0089 0090 class TextEditNoUserPropertyNoNotifyWidget : public QWidget 0091 { 0092 Q_OBJECT 0093 Q_PROPERTY(QString text READ text WRITE setText) 0094 Q_PROPERTY(QString other READ other WRITE setOther NOTIFY otherChanged USER true) 0095 public: 0096 TextEditNoUserPropertyNoNotifyWidget(QWidget *parent = nullptr) 0097 : QWidget(parent) 0098 { 0099 } 0100 void setText(const QString &text) 0101 { 0102 m_text = text; 0103 Q_EMIT textChanged(m_text); 0104 } 0105 QString text() const 0106 { 0107 return m_text; 0108 } 0109 void setOther(const QString &other) 0110 { 0111 m_other = other; 0112 Q_EMIT textChanged(m_other); 0113 } 0114 QString other() const 0115 { 0116 return m_other; 0117 } 0118 Q_SIGNALS: 0119 void textChanged(const QString &text); 0120 void otherChanged(const QString &other); 0121 0122 private: 0123 QString m_text; 0124 QString m_other; 0125 }; 0126 0127 class ComboBoxPage : public QWidget 0128 { 0129 public: 0130 ComboBoxPage() 0131 { 0132 colorCombo = new KColorCombo(this); 0133 colorCombo->setObjectName(QStringLiteral("kcfg_Color")); 0134 colorCombo->setColor(Qt::red); 0135 0136 enumCombo = new QComboBox(this); 0137 enumCombo->setObjectName(QStringLiteral("kcfg_Enum")); 0138 enumCombo->addItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); 0139 0140 textCombo = new QComboBox(this); 0141 textCombo->setObjectName(QStringLiteral("kcfg_Text")); 0142 textCombo->setEditable(true); 0143 textCombo->addItems(QStringList() << QStringLiteral("A") << QStringLiteral("B") << QStringLiteral("C")); 0144 0145 numInput = new QSpinBox(this); 0146 numInput->setValue(1); 0147 numInput->setObjectName(QStringLiteral("kcfg_IntNumInput")); 0148 } 0149 0150 KColorCombo *colorCombo; 0151 QComboBox *enumCombo; 0152 QComboBox *textCombo; 0153 QSpinBox *numInput; 0154 }; 0155 0156 class ComboSettings : public KConfigSkeleton 0157 { 0158 public: 0159 ComboSettings() 0160 : KConfigSkeleton(CONFIG_FILE) 0161 { 0162 colorItem = new ItemColor(currentGroup(), QStringLiteral("Color"), color, Qt::white); 0163 addItem(colorItem, QStringLiteral("Color")); 0164 0165 QList<ItemEnum::Choice> textValues; 0166 { 0167 ItemEnum::Choice choice; 0168 choice.name = QStringLiteral("A"); 0169 textValues.append(choice); 0170 } 0171 { 0172 ItemEnum::Choice choice; 0173 choice.name = QStringLiteral("B"); 0174 textValues.append(choice); 0175 } 0176 { 0177 ItemEnum::Choice choice; 0178 choice.name = QStringLiteral("C"); 0179 textValues.append(choice); 0180 } 0181 enumItem = new ItemEnum(currentGroup(), QStringLiteral("Enum"), enumIndex, textValues, 1); 0182 addItem(enumItem, QStringLiteral("Enum")); 0183 0184 stringItem = new ItemString(currentGroup(), QStringLiteral("Text"), string, QStringLiteral("hh:mm")); 0185 addItem(stringItem, QStringLiteral("Text")); 0186 0187 intValueItem = new ItemInt(currentGroup(), QStringLiteral("IntNumInput"), intValue, 42); 0188 addItem(intValueItem, QStringLiteral("IntNumInput")); 0189 } 0190 0191 ItemColor *colorItem; 0192 QColor color; 0193 0194 ItemEnum *enumItem; 0195 int enumIndex; 0196 0197 ItemString *stringItem; 0198 QString string; 0199 0200 ItemInt *intValueItem; 0201 int intValue; 0202 }; 0203 0204 class KConfigDialog_UnitTest : public QObject 0205 { 0206 Q_OBJECT 0207 0208 private Q_SLOTS: 0209 void initTestCase() 0210 { 0211 QStandardPaths::setTestModeEnabled(true); 0212 // Leftover configuration breaks combosTest 0213 const QString configFile = QStandardPaths::locate(QStandardPaths::GenericConfigLocation, CONFIG_FILE); 0214 if (!configFile.isEmpty()) { 0215 if (!QFile::remove(configFile)) { 0216 qWarning() << "Could not remove old config file:" << configFile; 0217 } 0218 } 0219 } 0220 0221 void test() 0222 { 0223 ComboSettings *skeleton = new ComboSettings(); 0224 KConfigDialog *dialog = new KConfigDialog(nullptr, QStringLiteral("settings"), skeleton); 0225 ComboBoxPage *page = new ComboBoxPage(); 0226 0227 QCOMPARE(page->colorCombo->color().name(), QColor(Qt::red).name()); 0228 QCOMPARE(page->enumCombo->currentIndex(), 0); 0229 QCOMPARE(page->textCombo->currentText(), QString("A")); 0230 QCOMPARE(page->numInput->value(), 1); 0231 0232 dialog->addPage(page, QStringLiteral("General")); 0233 0234 QCOMPARE(page->colorCombo->color().name(), QColor(Qt::white).name()); 0235 QCOMPARE(page->enumCombo->currentIndex(), 1); 0236 QCOMPARE(page->textCombo->currentText(), QLatin1String("hh:mm")); 0237 QCOMPARE(page->numInput->value(), 42); 0238 0239 page->colorCombo->setColor(Qt::blue); 0240 page->enumCombo->setCurrentIndex(2); 0241 page->textCombo->setCurrentIndex(2); 0242 page->numInput->setValue(2); 0243 0244 QDialogButtonBox *buttonBox = dialog->findChild<QDialogButtonBox *>(); 0245 QVERIFY(buttonBox != nullptr); 0246 buttonBox->button(QDialogButtonBox::Apply)->click(); 0247 QCOMPARE(skeleton->colorItem->property().value<QColor>().name(), QColor(Qt::blue).name()); 0248 QCOMPARE(skeleton->enumItem->property().toInt(), 2); 0249 QCOMPARE(skeleton->stringItem->property().toString(), QLatin1String("C")); 0250 QCOMPARE(skeleton->intValueItem->property().toInt(), 2); 0251 0252 delete dialog; 0253 delete skeleton; 0254 } 0255 0256 void testKConfigCompilerSignalsKnownWidget() 0257 { 0258 QLineEdit *edit = new QLineEdit; 0259 0260 testKConfigCompilerSignals<QLineEdit>(edit, QStringLiteral("settings2")); 0261 } 0262 0263 void testKConfigCompilerSignalsWithUserProperty() 0264 { 0265 // make sure there is nothing registered for the property 0266 KConfigDialogManager::propertyMap()->remove("TextEditUserPropertyWidget"); 0267 0268 TextEditUserPropertyWidget *edit = new TextEditUserPropertyWidget; 0269 0270 testKConfigCompilerSignals<TextEditUserPropertyWidget>(edit, QStringLiteral("settings3")); 0271 } 0272 0273 void testKConfigCompilerSignalsWithoutUserPropertyByMap() 0274 { 0275 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyWidget", QByteArray("text")); 0276 0277 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0278 0279 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings4")); 0280 } 0281 0282 void testKConfigCompilerSignalsWithoutUserPropertyByProperty() 0283 { 0284 // make sure there is nothing registered for the property 0285 KConfigDialogManager::propertyMap()->remove("TextEditNoUserPropertyWidget"); 0286 0287 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0288 edit->setProperty("kcfg_property", QByteArray("text")); 0289 0290 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings5")); 0291 } 0292 0293 void testKConfigCompilerSignalsWithUserPropertyAutoSignal() 0294 { 0295 // make sure there is nothing registered 0296 KConfigDialogManager::propertyMap()->remove("TextEditUserPropertyWidget"); 0297 0298 TextEditUserPropertyWidget *edit = new TextEditUserPropertyWidget; 0299 0300 testKConfigCompilerSignals<TextEditUserPropertyWidget>(edit, QStringLiteral("settings6")); 0301 } 0302 0303 void testKConfigCompilerSignalsWithoutUserPropertyByMapAutoSignal() 0304 { 0305 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyWidget", QByteArray("text")); 0306 0307 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0308 0309 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings7")); 0310 } 0311 0312 void testKConfigCompilerSignalsWithoutUserPropertyByPropertyAutoSignal() 0313 { 0314 // next to USER on "other" property, this one should also be ignored 0315 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyWidget", QByteArray("other")); 0316 0317 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0318 edit->setProperty("kcfg_property", QByteArray("text")); 0319 0320 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings8")); 0321 } 0322 0323 void testKConfigCompilerSignalsWithoutUserPropertyByPropertyBySignal() 0324 { 0325 // next to USER being on "other" property, this one should also be ignored 0326 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyNoNotifyWidget", QByteArray("other")); 0327 0328 TextEditNoUserPropertyNoNotifyWidget *edit = new TextEditNoUserPropertyNoNotifyWidget; 0329 edit->setProperty("kcfg_property", QByteArray("text")); 0330 edit->setProperty("kcfg_propertyNotify", SIGNAL(textChanged(QString))); 0331 0332 testKConfigCompilerSignals<TextEditNoUserPropertyNoNotifyWidget>(edit, QStringLiteral("settings9")); 0333 } 0334 0335 private: 0336 template<class T> 0337 void testKConfigCompilerSignals(T *edit, const QString &configDialogTitle) 0338 { 0339 const QString defaultValue = QStringLiteral("default value"); 0340 const QString changedValue = QStringLiteral("changed value"); 0341 const QString someOtherValue = QStringLiteral("some other value"); 0342 // set to default to ensure no old stored values make things fail 0343 SignalTest::self()->setDefaults(); 0344 KConfigDialog *dialog = new KConfigDialog(nullptr, configDialogTitle, SignalTest::self()); 0345 QWidget *page = new QWidget; 0346 edit->setParent(page); 0347 edit->setObjectName(QStringLiteral("kcfg_foo")); 0348 edit->setText(QStringLiteral("some text")); 0349 0350 QSignalSpy spy(SignalTest::self(), &SignalTest::fooChanged); 0351 QVERIFY(spy.isValid()); 0352 // now all the magic happens 0353 dialog->addPage(page, QStringLiteral("General")); 0354 0355 // check that default value gets loaded 0356 QCOMPARE(spy.size(), 0); 0357 QCOMPARE(edit->text(), defaultValue); 0358 QCOMPARE(SignalTest::foo(), defaultValue); 0359 0360 edit->setText(changedValue); 0361 // change signal should not be emitted immediately (only on save) 0362 QCOMPARE(spy.size(), 0); 0363 QCOMPARE(SignalTest::foo(), defaultValue); // should be no change to skeleton 0364 0365 QDialogButtonBox *buttonBox = dialog->findChild<QDialogButtonBox *>(); 0366 QVERIFY(buttonBox != nullptr); 0367 buttonBox->button(QDialogButtonBox::Apply)->click(); // now signal should be emitted 0368 0369 QCOMPARE(spy.size(), 1); 0370 QVariantList args = spy.last(); 0371 QCOMPARE(args.size(), 1); 0372 QCOMPARE((QMetaType::Type)args[0].userType(), QMetaType::QString); 0373 QCOMPARE(args[0].toString(), changedValue); 0374 QCOMPARE(SignalTest::foo(), changedValue); 0375 0376 // change it to a different value 0377 edit->setText(someOtherValue); 0378 QCOMPARE(spy.size(), 1); 0379 buttonBox->button(QDialogButtonBox::Apply)->click(); // now signal should be emitted 0380 0381 QCOMPARE(spy.size(), 2); 0382 args = spy.last(); 0383 QCOMPARE(args.size(), 1); 0384 QCOMPARE((QMetaType::Type)args[0].userType(), QMetaType::QString); 0385 QCOMPARE(args[0].toString(), someOtherValue); 0386 QCOMPARE(SignalTest::foo(), someOtherValue); 0387 } 0388 }; 0389 0390 QTEST_MAIN(KConfigDialog_UnitTest) 0391 0392 #include "kconfigdialog_unittest.moc"