diff --git a/autotests/kconfigskeletontest.h b/autotests/kconfigskeletontest.h --- a/autotests/kconfigskeletontest.h +++ b/autotests/kconfigskeletontest.h @@ -15,14 +15,17 @@ private Q_SLOTS: void initTestCase(); + void cleanupTestCase(); void init(); void cleanup(); void testSimple(); void testDefaults(); void testRemoveItem(); void testClear(); void testKConfigDirty(); void testSaveRead(); + void testDefaultFromFile(); + void testSetValueToOverridenDefaultCppValue(); private: KConfigSkeleton *s; diff --git a/autotests/kconfigskeletontest.cpp b/autotests/kconfigskeletontest.cpp --- a/autotests/kconfigskeletontest.cpp +++ b/autotests/kconfigskeletontest.cpp @@ -22,6 +22,16 @@ #define WRITE_SETTING3 QFont("helvetica",14) #define WRITE_SETTING4 QString("KDE") +static inline QString kdeGlobalsPath() +{ + return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kdeglobals"; +} + +static inline QString kdeSystemGlobalsPath() +{ + return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/system.kdeglobals"; +} + void KConfigSkeletonTest::initTestCase() { QStandardPaths::setTestModeEnabled(true); @@ -53,6 +63,16 @@ delete s; } +void KConfigSkeletonTest::cleanupTestCase() +{ + if (QFile::exists(kdeGlobalsPath())) { + QVERIFY(QFile::remove(kdeGlobalsPath())); + } + if (QFile::exists(kdeSystemGlobalsPath())) { + QVERIFY(QFile::remove(kdeSystemGlobalsPath())); + } +} + void KConfigSkeletonTest::testSimple() { mMyBool = WRITE_SETTING1; @@ -166,3 +186,70 @@ s->read(); QCOMPARE(mMyBool, false); } + +void KConfigSkeletonTest::testDefaultFromFile() +{ + // This test ensures we don't override default value when this one came from a file + // system.kdeglobals is a global file and can provide default + + // Add global as value for testDefault in system.kdeglobals. + // This value will became the new default + KConfig glob(QStringLiteral("system.kdeglobals")); + KConfigGroup generalGlob(&glob, "General"); + generalGlob.writeEntry("testDefault", "global"); + QVERIFY(glob.sync()); + + QString value; + s->load(); + s->setCurrentGroup(QStringLiteral("General")); + auto item = s->addItemString(QStringLiteral("testDefault"), value, QStringLiteral("defaultcpp")); + s->save(); + s->load(); + // Expected value at this point is default value and default value came from system.kdeglobals -> "global" + QCOMPARE(item->value(), QStringLiteral("global")); + + // Set value to a custom value + item->setValue(QStringLiteral("custom")); + s->save(); + s->load(); + // Expected value is now our custom value + QCOMPARE(item->value(), QStringLiteral("custom")); + + // Reset to defaults + s->setDefaults(); + s->save(); + s->load(); + // Default value is still global + QCOMPARE(item->value(), QStringLiteral("global")); + + // Change default value + generalGlob.writeEntry("testDefault", "globalv2"); + QVERIFY(glob.sync()); + + // expect globalv2 as default value and we don't expect global to be wrote on kconfigskeletontestrc + s->load(); + + // Add item to force readDefault + s->addItemString(QStringLiteral("testDefault"), value, QStringLiteral("defaultcpp")); + s->save(); + s->load(); + QCOMPARE(item->value(), QStringLiteral("globalv2")); +} + +void KConfigSkeletonTest::testSetValueToOverridenDefaultCppValue() +{ + // ensure we don't have any regression if we set value to cpp default value and we have a system default + KConfig glob(QStringLiteral("system.kdeglobals")); + KConfigGroup generalGlob(&glob, "General"); + generalGlob.writeEntry("testRegression", "global"); + QVERIFY(glob.sync()); + + QString value; + s->load(); + s->setCurrentGroup(QStringLiteral("General")); + auto item = s->addItemString(QStringLiteral("testRegression"), value, QStringLiteral("defaultcpp")); + item->setValue("defaultcpp"); + s->save(); + s->load(); + QCOMPARE(item->value(), QStringLiteral("defaultcpp")); +} diff --git a/autotests/kconfigtest.h b/autotests/kconfigtest.h --- a/autotests/kconfigtest.h +++ b/autotests/kconfigtest.h @@ -74,6 +74,7 @@ void testThreads(); void testKdeglobalsVsDefault(); + void testDefaultFromFile(); // should be last void testSyncOnExit(); diff --git a/autotests/kconfigtest.cpp b/autotests/kconfigtest.cpp --- a/autotests/kconfigtest.cpp +++ b/autotests/kconfigtest.cpp @@ -1976,3 +1976,58 @@ local.reparseConfiguration(); QCOMPARE(generalLocal.readEntry("testRestore", "defaultcpp"), "defaultcpp"); } + +void KConfigTest::testDefaultFromFile() +{ + // Add "configdefault" value to testKeyDefault in system.kdekdeglobals (this file provide default value) + KConfig glob(QStringLiteral("system.kdeglobals")); + KConfigGroup generalGlob(&glob, "General"); + generalGlob.writeEntry("testKeyDefault", "configdefault"); + QVERIFY(glob.sync()); + + const char *localFile = TEST_SUBDIR "testdefaultfromfilerc"; + KConfig local(QStringLiteral(TEST_SUBDIR "testdefaultfromfilerc")); + KConfigGroup generalLocal(&local, "General"); + // Check if we get global and not the default value from cpp (defaultcpp) when reading data from testdefaultfromfilerc + QCOMPARE(generalLocal.readEntry("testKeyDefault", "defaultcpp"), "configdefault"); + + // Write configdefault to local file + generalLocal.writeEntry("testKeyDefault", "configdefault"); + QVERIFY(local.sync()); + local.reparseConfiguration(); + // We expect to get configdefault value and configdefault not written to local file (file will not exist) + QCOMPARE(generalLocal.readEntry("testKeyDefault", "defaultcpp"), "configdefault"); + QVERIFY(!QFile::exists(localFile)); + + // Write a custom value, we expect this value to be written to local file + generalLocal.writeEntry("testKeyDefault", "custom"); + QVERIFY(local.sync()); + local.reparseConfiguration(); + QCOMPARE(generalLocal.readEntry("testKeyDefault", "defaultcpp"), "custom"); + QList lines = readLines(localFile); + Q_ASSERT(lines.contains("testKeyDefault=custom\n")); + + // Revert to default, we expect to get default value from file and local file don't exist + // To revert to file default we need to write same value + generalLocal.writeEntry("testKeyDefault", "configdefault"); + QVERIFY(local.sync()); + local.reparseConfiguration(); + QCOMPARE(generalLocal.readEntry("testKeyDefault", "defaultcpp"), "configdefault"); + + // Now we change default value from system.globals to ensure new one is used + glob.deleteGroup("General"); + glob.sync(); + glob.reparseConfiguration(); + generalGlob.writeEntry("testKeyDefault", "configdefault-new"); + QVERIFY(generalGlob.sync()); + local.reparseConfiguration(); + QCOMPARE(generalLocal.readEntry("testKeyDefault", "defaultcpp"), "configdefault-new"); + + // Set value to defaultcpp, this one need to be wrote to local file (so we don't end up with default from global file) + generalLocal.writeEntry("testKeyDefault", "defaultcpp"); + QVERIFY(local.sync()); + local.reparseConfiguration(); + QCOMPARE(generalLocal.readEntry("testKeyDefault", "defaultcpp"), "defaultcpp"); + lines = readLines(localFile); + Q_ASSERT(lines.contains("testKeyDefault=defaultcpp\n")); +} diff --git a/src/core/kconfigdata.cpp b/src/core/kconfigdata.cpp --- a/src/core/kconfigdata.cpp +++ b/src/core/kconfigdata.cpp @@ -166,6 +166,16 @@ } if (it.value() != e) { //qDebug() << "changing" << k << "from" << e.mValue << "to" << value; + if (e.bOverridesGlobal) { + // Check we are not setting back data to global value, in that case delete override + KEntryKey defaultKey(group, key, options & EntryLocalized, true); + const Iterator itDefault = find(defaultKey); + if (itDefault != end() && itDefault->mValue == e.mValue ) { + e.bReverted = true; + insert(k, e); + return true; + } + } it.value() = e; if (k.bDefault) { KEntryKey nonDefaultKey(k); @@ -214,9 +224,13 @@ QString KEntryMap::getEntry(const QByteArray &group, const QByteArray &key, const QString &defaultValue, KEntryMap::SearchFlags flags, bool *expand) const { - const ConstIterator it = findEntry(group, key, flags); + ConstIterator it = findEntry(group, key, flags); QString theValue = defaultValue; + // If entry is deleted fallback to default one + if (it != constEnd() && it->bDeleted) { + it = findEntry(group, key, flags | KEntryMap::SearchDefaults); + } if (it != constEnd() && !it->bDeleted) { if (!it->mValue.isNull()) { const QByteArray data = it->mValue;