File indexing completed on 2024-05-12 15:34:03

0001 /*
0002     SPDX-FileCopyrightText: 2014 Alexander Richardson <alex.richardson@gmx.de>
0003 
0004     SPDX-License-Identifier: MIT
0005 */
0006 
0007 #include "signals_test_no_singleton.h"
0008 #include "signals_test_no_singleton_dpointer.h"
0009 #include "signals_test_singleton.h"
0010 #include "signals_test_singleton_dpointer.h"
0011 #include "signals_test_singleton_itemaccessors.h"
0012 #include <QDebug>
0013 #include <QFileInfo>
0014 #include <QSignalSpy>
0015 #include <QTemporaryFile>
0016 #include <QtGlobal>
0017 #include <QtTestGui>
0018 #include <functional>
0019 
0020 class KConfigCompiler_Test_Signals : public QObject
0021 {
0022     Q_OBJECT
0023 private Q_SLOTS:
0024     void testSetters();
0025     void testSetters_data();
0026     void testSetProperty();
0027     void testSetProperty_data();
0028     void initTestCase();
0029     void cleanupTestCase();
0030 };
0031 
0032 static SignalsTestNoSingleton *noSingleton;
0033 static SignalsTestNoSingletonDpointer *noSingletonDpointer;
0034 
0035 void KConfigCompiler_Test_Signals::initTestCase()
0036 {
0037     // These tests do a lot quite a few I/O operations, speed that up by using a QTemporaryFile.
0038     // At least on Linux this is often a tmpfs which means only RAM operations
0039     QTemporaryFile *tempFile1 = new QTemporaryFile(this);
0040     QTemporaryFile *tempFile2 = new QTemporaryFile(this);
0041     QTemporaryFile *tempFile3 = new QTemporaryFile(this);
0042     QTemporaryFile *tempFile4 = new QTemporaryFile(this);
0043     QTemporaryFile *tempFile5 = new QTemporaryFile(this);
0044     QVERIFY(tempFile1->open());
0045     QVERIFY(tempFile2->open());
0046     QVERIFY(tempFile3->open());
0047     QVERIFY(tempFile4->open());
0048     QVERIFY(tempFile5->open());
0049 
0050     SignalsTestSingleton::instance(QFileInfo(*tempFile1).absoluteFilePath());
0051     SignalsTestSingletonDpointer::instance(QFileInfo(*tempFile2).absoluteFilePath());
0052     noSingleton = new SignalsTestNoSingleton(KSharedConfig::openConfig(QFileInfo(*tempFile3).absoluteFilePath(), KConfig::SimpleConfig));
0053     noSingletonDpointer = new SignalsTestNoSingletonDpointer(KSharedConfig::openConfig(QFileInfo(*tempFile4).absoluteFilePath(), KConfig::SimpleConfig));
0054     SignalsTestSingletonItemAccessors::instance(QFileInfo(*tempFile5).absoluteFilePath());
0055 }
0056 
0057 void KConfigCompiler_Test_Signals::cleanupTestCase()
0058 {
0059     // ensure these instances are deleted before the temporary files are closed
0060     delete noSingleton;
0061     delete noSingletonDpointer;
0062     delete SignalsTestSingleton::self();
0063     delete SignalsTestSingletonDpointer::self();
0064     delete SignalsTestSingletonItemAccessors::self();
0065 }
0066 
0067 struct TestSettersArg {
0068     // default constructor required for Q_DECLARE_METATYPE
0069     TestSettersArg()
0070         : obj(nullptr)
0071     {
0072     }
0073     template<typename T>
0074     TestSettersArg(T *object)
0075         : obj(object)
0076     {
0077         // we can also call static methods using object->foo() so this works for all four cases
0078         getter = [object]() {
0079             return object->foo();
0080         };
0081         defaultGetter = [object]() {
0082             return object->defaultFooValue();
0083         };
0084         setter = [object](const QString &s) {
0085             object->setFoo(s);
0086         };
0087     }
0088     KCoreConfigSkeleton *obj;
0089     std::function<QString()> getter;
0090     std::function<QString()> defaultGetter;
0091     std::function<void(const QString &)> setter;
0092 };
0093 
0094 Q_DECLARE_METATYPE(TestSettersArg) // so that QFETCH works
0095 
0096 void KConfigCompiler_Test_Signals::testSetters_data()
0097 {
0098     QTest::addColumn<TestSettersArg>("params");
0099     QTest::newRow("singleton") << TestSettersArg(SignalsTestSingleton::self());
0100     QTest::newRow("singleton dpointer") << TestSettersArg(SignalsTestSingletonDpointer::self());
0101     QTest::newRow("non-singleton") << TestSettersArg(noSingleton);
0102     QTest::newRow("non-singleton dpointer") << TestSettersArg(noSingleton);
0103     QTest::newRow("singleton itemaccessors") << TestSettersArg(SignalsTestSingletonItemAccessors::self());
0104 }
0105 
0106 /** Ensure that a signal is emitted whenever the data is changed by using the generated setters */
0107 void KConfigCompiler_Test_Signals::testSetters()
0108 {
0109     QFETCH(TestSettersArg, params);
0110     const char *signal = SIGNAL(fooChanged(QString));
0111     const QString defaultValue = QStringLiteral("default");
0112     const QString changedValue = QStringLiteral("changed");
0113 
0114     // make sure we are in the default state
0115     params.obj->setDefaults();
0116     params.obj->save();
0117 
0118     QList<QVariant> args;
0119     QSignalSpy spy(params.obj, signal);
0120     QVERIFY2(spy.isValid(), signal);
0121 
0122     // change value via setter, should get signal
0123     QCOMPARE(params.getter(), defaultValue);
0124     QCOMPARE(defaultValue, params.defaultGetter());
0125     QCOMPARE(params.getter(), params.defaultGetter());
0126     QVERIFY(changedValue != params.getter());
0127     params.setter(changedValue);
0128     QCOMPARE(params.getter(), changedValue);
0129     QCOMPARE(spy.count(), 0); // should have no change yet, only after save()
0130     params.obj->save();
0131     QCOMPARE(spy.count(), 1);
0132     args = spy.takeFirst();
0133     QCOMPARE(args.size(), 1);
0134     QCOMPARE(args[0].toString(), changedValue);
0135 
0136     // reset to default values via setDefaults()
0137     QVERIFY(params.getter() != params.defaultGetter());
0138     QVERIFY(params.getter() != defaultValue);
0139     QCOMPARE(params.getter(), changedValue);
0140     params.obj->setDefaults();
0141     QCOMPARE(params.getter(), params.defaultGetter());
0142     QCOMPARE(params.getter(), defaultValue);
0143 
0144     QCOMPARE(spy.count(), 0); // should have no change yet, only after save()
0145     params.obj->save();
0146     // TODO: This currently fails since setDefaults() does not yet cause emitting a signal
0147     QCOMPARE(spy.count(), 1);
0148     args = spy.takeFirst();
0149     QCOMPARE(args.size(), 1);
0150     QCOMPARE(args[0].value<QString>(), defaultValue);
0151 }
0152 
0153 Q_DECLARE_METATYPE(KCoreConfigSkeleton *)
0154 
0155 void KConfigCompiler_Test_Signals::testSetProperty_data()
0156 {
0157     QTest::addColumn<KCoreConfigSkeleton *>("obj");
0158     QTest::newRow("singleton") << static_cast<KCoreConfigSkeleton *>(SignalsTestSingleton::self());
0159     QTest::newRow("singleton dpointer") << static_cast<KCoreConfigSkeleton *>(SignalsTestSingletonDpointer::self());
0160     QTest::newRow("non-singleton") << static_cast<KCoreConfigSkeleton *>(noSingleton);
0161     QTest::newRow("non-singleton dpointer") << static_cast<KCoreConfigSkeleton *>(noSingletonDpointer);
0162     QTest::newRow("singleton itemaccessors") << static_cast<KCoreConfigSkeleton *>(SignalsTestSingletonItemAccessors::self());
0163 }
0164 
0165 /** Test that the signal is emitted when modifying the values using the underlying KConfigSkeletonItem (bypassing the setters) */
0166 void KConfigCompiler_Test_Signals::testSetProperty()
0167 {
0168     QFETCH(KCoreConfigSkeleton *, obj);
0169     const char *signal = SIGNAL(fooChanged(QString));
0170     const QString propertyName = QStringLiteral("foo");
0171     const QString defaultValue = QStringLiteral("default");
0172     const QString newValue = QStringLiteral("changed");
0173     obj->setDefaults();
0174     obj->save();
0175 
0176     KConfigSkeletonItem *item = obj->findItem(propertyName);
0177     QVERIFY2(item, "Item must exist");
0178     QVERIFY2(!item->isImmutable(), "Item must not be immutable");
0179     QVERIFY2(!obj->isImmutable(propertyName), "Item must not be immutable");
0180 
0181     // listen for all expected signals
0182     QSignalSpy spy(obj, signal);
0183     QVERIFY2(spy.isValid(), signal);
0184 
0185     QVERIFY(item->isEqual(defaultValue));
0186     QVERIFY(!item->isEqual(newValue));
0187 
0188     item->setProperty(newValue); // change value now
0189     // should have no change yet, only after save()
0190     QCOMPARE(spy.count(), 0);
0191     obj->save();
0192     // now check for the signal emissions
0193     QCOMPARE(spy.count(), 1);
0194     QList<QVariant> args = spy.takeFirst();
0195     QCOMPARE(args.size(), 1);
0196     QVERIFY(item->isEqual(args[0]));
0197 
0198     // now reset to default
0199     QVERIFY(!item->isEqual(defaultValue));
0200     item->setDefault();
0201     QVERIFY(item->isEqual(defaultValue));
0202     // should have no change yet, only after save()
0203     QCOMPARE(spy.count(), 0);
0204     obj->save();
0205     // now check for the signal emissions
0206     QCOMPARE(spy.count(), 1);
0207     args = spy.takeFirst();
0208     QCOMPARE(args.size(), 1);
0209     QVERIFY(item->isEqual(args[0]));
0210 }
0211 
0212 QTEST_MAIN(KConfigCompiler_Test_Signals)
0213 
0214 #include "kconfigcompiler_test_signals.moc"