File indexing completed on 2024-04-28 11:34:42
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 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0269 KConfigDialogManager::changedMap()->insert("TextEditUserPropertyWidget", SIGNAL(textChanged(QString))); 0270 #endif 0271 0272 TextEditUserPropertyWidget *edit = new TextEditUserPropertyWidget; 0273 0274 testKConfigCompilerSignals<TextEditUserPropertyWidget>(edit, QStringLiteral("settings3")); 0275 } 0276 0277 void testKConfigCompilerSignalsWithoutUserPropertyByMap() 0278 { 0279 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0280 KConfigDialogManager::changedMap()->insert("TextEditNoUserPropertyWidget", SIGNAL(textChanged(QString))); 0281 #endif 0282 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyWidget", QByteArray("text")); 0283 0284 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0285 0286 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings4")); 0287 } 0288 0289 void testKConfigCompilerSignalsWithoutUserPropertyByProperty() 0290 { 0291 // make sure there is nothing registered for the property 0292 KConfigDialogManager::propertyMap()->remove("TextEditNoUserPropertyWidget"); 0293 0294 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0295 KConfigDialogManager::changedMap()->insert("TextEditNoUserPropertyWidget", SIGNAL(textChanged(QString))); 0296 #endif 0297 0298 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0299 edit->setProperty("kcfg_property", QByteArray("text")); 0300 0301 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings5")); 0302 } 0303 0304 void testKConfigCompilerSignalsWithUserPropertyAutoSignal() 0305 { 0306 // make sure there is nothing registered 0307 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0308 KConfigDialogManager::changedMap()->remove("TextEditUserPropertyWidget"); 0309 #endif 0310 KConfigDialogManager::propertyMap()->remove("TextEditUserPropertyWidget"); 0311 0312 TextEditUserPropertyWidget *edit = new TextEditUserPropertyWidget; 0313 0314 testKConfigCompilerSignals<TextEditUserPropertyWidget>(edit, QStringLiteral("settings6")); 0315 } 0316 0317 void testKConfigCompilerSignalsWithoutUserPropertyByMapAutoSignal() 0318 { 0319 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0320 // make sure there is nothing registered for the signal 0321 KConfigDialogManager::changedMap()->remove("TextEditNoUserPropertyWidget"); 0322 #endif 0323 0324 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyWidget", QByteArray("text")); 0325 0326 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0327 0328 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings7")); 0329 } 0330 0331 void testKConfigCompilerSignalsWithoutUserPropertyByPropertyAutoSignal() 0332 { 0333 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0334 // make sure there is no signal registered 0335 KConfigDialogManager::changedMap()->remove("TextEditNoUserPropertyWidget"); 0336 #endif 0337 // next to USER on "other" property, this one should also be ignored 0338 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyWidget", QByteArray("other")); 0339 0340 TextEditNoUserPropertyWidget *edit = new TextEditNoUserPropertyWidget; 0341 edit->setProperty("kcfg_property", QByteArray("text")); 0342 0343 testKConfigCompilerSignals<TextEditNoUserPropertyWidget>(edit, QStringLiteral("settings8")); 0344 } 0345 0346 void testKConfigCompilerSignalsWithoutUserPropertyByPropertyBySignal() 0347 { 0348 // next to USER being on "other" property, this one should also be ignored 0349 #if KCONFIGWIDGETS_ENABLE_DEPRECATED_SINCE(5, 32) 0350 KConfigDialogManager::changedMap()->insert("TextEditNoUserPropertyNoNotifyWidget", SIGNAL(otherChanged(QString))); 0351 #endif 0352 KConfigDialogManager::propertyMap()->insert("TextEditNoUserPropertyNoNotifyWidget", QByteArray("other")); 0353 0354 TextEditNoUserPropertyNoNotifyWidget *edit = new TextEditNoUserPropertyNoNotifyWidget; 0355 edit->setProperty("kcfg_property", QByteArray("text")); 0356 edit->setProperty("kcfg_propertyNotify", SIGNAL(textChanged(QString))); 0357 0358 testKConfigCompilerSignals<TextEditNoUserPropertyNoNotifyWidget>(edit, QStringLiteral("settings9")); 0359 } 0360 0361 private: 0362 template<class T> 0363 void testKConfigCompilerSignals(T *edit, const QString &configDialogTitle) 0364 { 0365 const QString defaultValue = QStringLiteral("default value"); 0366 const QString changedValue = QStringLiteral("changed value"); 0367 const QString someOtherValue = QStringLiteral("some other value"); 0368 // set to default to ensure no old stored values make things fail 0369 SignalTest::self()->setDefaults(); 0370 KConfigDialog *dialog = new KConfigDialog(nullptr, configDialogTitle, SignalTest::self()); 0371 QWidget *page = new QWidget; 0372 edit->setParent(page); 0373 edit->setObjectName(QStringLiteral("kcfg_foo")); 0374 edit->setText(QStringLiteral("some text")); 0375 0376 QSignalSpy spy(SignalTest::self(), &SignalTest::fooChanged); 0377 QVERIFY(spy.isValid()); 0378 // now all the magic happens 0379 dialog->addPage(page, QStringLiteral("General")); 0380 0381 // check that default value gets loaded 0382 QCOMPARE(spy.size(), 0); 0383 QCOMPARE(edit->text(), defaultValue); 0384 QCOMPARE(SignalTest::foo(), defaultValue); 0385 0386 edit->setText(changedValue); 0387 // change signal should not be emitted immediately (only on save) 0388 QCOMPARE(spy.size(), 0); 0389 QCOMPARE(SignalTest::foo(), defaultValue); // should be no change to skeleton 0390 0391 QDialogButtonBox *buttonBox = dialog->findChild<QDialogButtonBox *>(); 0392 QVERIFY(buttonBox != nullptr); 0393 buttonBox->button(QDialogButtonBox::Apply)->click(); // now signal should be emitted 0394 0395 QCOMPARE(spy.size(), 1); 0396 QVariantList args = spy.last(); 0397 QCOMPARE(args.size(), 1); 0398 QCOMPARE((QMetaType::Type)args[0].type(), QMetaType::QString); 0399 QCOMPARE(args[0].toString(), changedValue); 0400 QCOMPARE(SignalTest::foo(), changedValue); 0401 0402 // change it to a different value 0403 edit->setText(someOtherValue); 0404 QCOMPARE(spy.size(), 1); 0405 buttonBox->button(QDialogButtonBox::Apply)->click(); // now signal should be emitted 0406 0407 QCOMPARE(spy.size(), 2); 0408 args = spy.last(); 0409 QCOMPARE(args.size(), 1); 0410 QCOMPARE((QMetaType::Type)args[0].type(), QMetaType::QString); 0411 QCOMPARE(args[0].toString(), someOtherValue); 0412 QCOMPARE(SignalTest::foo(), someOtherValue); 0413 } 0414 }; 0415 0416 QTEST_MAIN(KConfigDialog_UnitTest) 0417 0418 #include "kconfigdialog_unittest.moc"