aboutsummaryrefslogtreecommitdiff
path: root/autotests/kconfigtest.cpp
diff options
context:
space:
mode:
authorJenkins CI <null@kde.org>2013-12-18 00:45:18 +0000
committerJenkins CI <null@kde.org>2013-12-18 00:45:18 +0000
commit867e7a50e6396338ab4fe9aa22ad141e4cd344d2 (patch)
tree1d6f8d6c912fa04dc268b5580bcfe696fa538743 /autotests/kconfigtest.cpp
parentc38b88497a833e482e6892b72c8f52adec6de857 (diff)
downloadkconfig-867e7a50e6396338ab4fe9aa22ad141e4cd344d2.tar.gz
kconfig-867e7a50e6396338ab4fe9aa22ad141e4cd344d2.tar.bz2
Move kconfig code to the root directory.
Diffstat (limited to 'autotests/kconfigtest.cpp')
-rw-r--r--autotests/kconfigtest.cpp1634
1 files changed, 1634 insertions, 0 deletions
diff --git a/autotests/kconfigtest.cpp b/autotests/kconfigtest.cpp
new file mode 100644
index 00000000..1aed5151
--- /dev/null
+++ b/autotests/kconfigtest.cpp
@@ -0,0 +1,1634 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 1997 Matthias Kalle Dalheimer (kalle@kde.org)
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+// Qt5 TODO: re-enable. No point in doing it before, it breaks on QString::fromUtf8(QByteArray), which exists in qt5.
+#undef QT_NO_CAST_FROM_BYTEARRAY
+
+#include "kconfigtest.h"
+
+#include <QtTest/QtTest>
+#include <qtemporarydir.h>
+#include <QStandardPaths>
+#include <kdesktopfile.h>
+
+#include <ksharedconfig.h>
+#include <kconfiggroup.h>
+
+#ifdef Q_OS_UNIX
+#include <utime.h>
+#endif
+#ifndef Q_OS_WIN
+#include <unistd.h> // gethostname
+#endif
+
+KCONFIGGROUP_DECLARE_ENUM_QOBJECT(KConfigTest,Testing)
+KCONFIGGROUP_DECLARE_FLAGS_QOBJECT(KConfigTest,Flags)
+
+QTEST_MAIN( KConfigTest )
+
+#define BOOLENTRY1 true
+#define BOOLENTRY2 false
+#define STRINGENTRY1 "hello"
+#define STRINGENTRY2 " hello"
+#define STRINGENTRY3 "hello "
+#define STRINGENTRY4 " hello "
+#define STRINGENTRY5 " "
+#define STRINGENTRY6 ""
+#define UTF8BITENTRY "Hello äöü"
+#define TRANSLATEDSTRINGENTRY1 "bonjour"
+#define BYTEARRAYENTRY QByteArray( "\x00\xff\x7f\x3c abc\x00\x00", 10 )
+#define ESCAPEKEY " []\0017[]==]"
+#define ESCAPEENTRY "[]\170[]]=3=]\\] "
+#define DOUBLEENTRY 123456.78912345
+#define FLOATENTRY 123.567f
+#define POINTENTRY QPoint( 4351, 1235 )
+#define SIZEENTRY QSize( 10, 20 )
+#define RECTENTRY QRect( 10, 23, 5321, 13 )
+#define DATETIMEENTRY QDateTime( QDate( 2002, 06, 23 ), QTime( 12, 55, 40 ) )
+#define STRINGLISTENTRY (QStringList( "Hello," ) << " World")
+#define STRINGLISTEMPTYENTRY QStringList()
+#define STRINGLISTJUSTEMPTYELEMENT QStringList(QString())
+#define STRINGLISTEMPTYTRAINLINGELEMENT (QStringList( "Hi" ) << QString())
+#define STRINGLISTESCAPEODDENTRY (QStringList( "Hello\\\\\\" ) << "World")
+#define STRINGLISTESCAPEEVENENTRY (QStringList( "Hello\\\\\\\\" ) << "World")
+#define STRINGLISTESCAPECOMMAENTRY (QStringList( "Hel\\\\\\,\\\\,\\,\\\\\\\\,lo" ) << "World")
+#define INTLISTENTRY1 QList<int>() << 1 << 2 << 3 << 4
+#define BYTEARRAYLISTENTRY1 QList<QByteArray>() << "" << "1,2" << "end"
+#define VARIANTLISTENTRY (QVariantList() << true << false << QString("joe") << 10023)
+#define VARIANTLISTENTRY2 (QVariantList() << POINTENTRY << SIZEENTRY)
+#define HOMEPATH QString(QDir::homePath()+"/foo")
+#define HOMEPATHESCAPE QString(QDir::homePath()+"/foo/$HOME")
+#define DOLLARGROUP "$i"
+
+void KConfigTest::initTestCase()
+{
+ // ensure we don't use files in the real config directory
+ QStandardPaths::setTestModeEnabled(true);
+ QString testConfigDir = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation);
+
+ // to make sure all files from a previous failed run are deleted
+ cleanupTestCase();
+
+
+ KConfig sc( "kconfigtest" );
+
+ KConfigGroup cg(&sc, "AAA");
+ cg.writeEntry("stringEntry1", STRINGENTRY1,
+ KConfig::Persistent|KConfig::Global);
+ cg.deleteEntry("stringEntry2", KConfig::Global);
+
+ cg = KConfigGroup(&sc, "Hello");
+ cg.writeEntry( "boolEntry1", BOOLENTRY1 );
+ cg.writeEntry( "boolEntry2", BOOLENTRY2 );
+
+ QByteArray data( UTF8BITENTRY );
+ QCOMPARE( data.size(), 12 ); // the source file is in utf8
+ QCOMPARE( QString::fromUtf8(data).length(), 9 );
+ cg.writeEntry ("Test", data);
+ cg.writeEntry( "bytearrayEntry", BYTEARRAYENTRY );
+ cg.writeEntry( ESCAPEKEY, ESCAPEENTRY );
+ cg.writeEntry( "emptyEntry", "");
+ cg.writeEntry( "stringEntry1", STRINGENTRY1 );
+ cg.writeEntry( "stringEntry2", STRINGENTRY2 );
+ cg.writeEntry( "stringEntry3", STRINGENTRY3 );
+ cg.writeEntry( "stringEntry4", STRINGENTRY4 );
+ cg.writeEntry( "stringEntry5", STRINGENTRY5 );
+ cg.writeEntry( "urlEntry1", QUrl("http://qt-project.org") );
+ cg.writeEntry( "keywith=equalsign", STRINGENTRY1 );
+ cg.deleteEntry( "stringEntry5" );
+ cg.deleteEntry( "stringEntry6" ); // deleting a nonexistent entry
+ cg.writeEntry( "byteArrayEntry1", QByteArray( STRINGENTRY1 ),
+ KConfig::Global|KConfig::Persistent );
+ cg.writeEntry( "doubleEntry1", DOUBLEENTRY );
+ cg.writeEntry( "floatEntry1", FLOATENTRY );
+
+ sc.deleteGroup("deleteMe"); // deleting a nonexistent group
+
+ cg = KConfigGroup(&sc, "Complex Types");
+ cg.writeEntry( "rectEntry", RECTENTRY );
+ cg.writeEntry( "pointEntry", POINTENTRY );
+ cg.writeEntry( "sizeEntry", SIZEENTRY );
+ cg.writeEntry( "dateTimeEntry", DATETIMEENTRY );
+ cg.writeEntry( "dateEntry", DATETIMEENTRY.date() );
+
+ KConfigGroup ct = cg;
+ cg = KConfigGroup(&ct, "Nested Group 1");
+ cg.writeEntry("stringentry1", STRINGENTRY1);
+
+ cg = KConfigGroup(&ct, "Nested Group 2");
+ cg.writeEntry( "stringEntry2", STRINGENTRY2 );
+
+ cg = KConfigGroup(&cg, "Nested Group 2.1");
+ cg.writeEntry( "stringEntry3", STRINGENTRY3 );
+
+ cg = KConfigGroup(&ct, "Nested Group 3");
+ cg.writeEntry( "stringEntry3", STRINGENTRY3 );
+
+ cg = KConfigGroup(&sc, "List Types" );
+ cg.writeEntry( "listOfIntsEntry1", INTLISTENTRY1 );
+ cg.writeEntry( "listOfByteArraysEntry1", BYTEARRAYLISTENTRY1 );
+ cg.writeEntry( "stringListEntry", STRINGLISTENTRY );
+ cg.writeEntry( "stringListEmptyEntry", STRINGLISTEMPTYENTRY );
+ cg.writeEntry( "stringListJustEmptyElement", STRINGLISTJUSTEMPTYELEMENT );
+ cg.writeEntry( "stringListEmptyTrailingElement", STRINGLISTEMPTYTRAINLINGELEMENT );
+ cg.writeEntry( "stringListEscapeOddEntry", STRINGLISTESCAPEODDENTRY );
+ cg.writeEntry( "stringListEscapeEvenEntry", STRINGLISTESCAPEEVENENTRY );
+ cg.writeEntry( "stringListEscapeCommaEntry", STRINGLISTESCAPECOMMAENTRY );
+ cg.writeEntry( "variantListEntry", VARIANTLISTENTRY );
+
+ cg = KConfigGroup(&sc, "Path Type" );
+ cg.writePathEntry( "homepath", HOMEPATH );
+ cg.writePathEntry( "homepathescape", HOMEPATHESCAPE );
+
+ cg = KConfigGroup(&sc, "Enum Types" );
+ writeEntry( cg, "enum-10", Tens );
+ writeEntry( cg, "enum-100", Hundreds );
+ writeEntry( cg, "flags-bit0", Flags(bit0));
+ writeEntry( cg, "flags-bit0-bit1", Flags(bit0|bit1) );
+
+ cg = KConfigGroup(&sc, "ParentGroup" );
+ KConfigGroup cg1(&cg, "SubGroup1" );
+ cg1.writeEntry( "somestring", "somevalue" );
+ cg.writeEntry( "parentgrpstring", "somevalue" );
+ KConfigGroup cg2(&cg, "SubGroup2" );
+ cg2.writeEntry( "substring", "somevalue" );
+ KConfigGroup cg3(&cg, "SubGroup/3");
+ cg3.writeEntry( "sub3string", "somevalue" );
+
+ QVERIFY(sc.isDirty());
+ QVERIFY(sc.sync());
+ QVERIFY(!sc.isDirty());
+
+ QVERIFY2(QFile::exists(testConfigDir + QStringLiteral("/kconfigtest")),
+ qPrintable(testConfigDir + QStringLiteral("/kconfigtest must exist")));
+ QVERIFY2(QFile::exists(testConfigDir + QStringLiteral("/kdeglobals")),
+ qPrintable(testConfigDir + QStringLiteral("/kdeglobals must exist")));
+
+
+ KConfig sc1("kdebugrc", KConfig::SimpleConfig);
+ KConfigGroup sg0(&sc1, "0");
+ sg0.writeEntry("AbortFatal", false);
+ sg0.writeEntry("WarnOutput", 0);
+ sg0.writeEntry("FatalOutput", 0);
+ QVERIFY(sc1.sync());
+
+ //Setup stuff to test KConfig::addConfigSources()
+ KConfig devcfg("specificrc");
+ KConfigGroup devonlygrp(&devcfg, "Specific Only Group");
+ devonlygrp.writeEntry("ExistingEntry", "DevValue");
+ KConfigGroup devandbasegrp(&devcfg, "Shared Group");
+ devandbasegrp.writeEntry("SomeSharedEntry", "DevValue");
+ devandbasegrp.writeEntry("SomeSpecificOnlyEntry", "DevValue");
+ QVERIFY(devcfg.sync());
+ KConfig basecfg("baserc");
+ KConfigGroup basegrp(&basecfg, "Base Only Group");
+ basegrp.writeEntry("ExistingEntry", "BaseValue");
+ KConfigGroup baseanddevgrp(&basecfg, "Shared Group");
+ baseanddevgrp.writeEntry("SomeSharedEntry", "BaseValue");
+ baseanddevgrp.writeEntry("SomeBaseOnlyEntry", "BaseValue");
+ QVERIFY(basecfg.sync());
+
+ KConfig gecfg("groupescapetest", KConfig::SimpleConfig);
+ cg = KConfigGroup(&gecfg, DOLLARGROUP);
+ cg.writeEntry( "entry", "doesntmatter" );
+
+}
+
+void KConfigTest::cleanupTestCase()
+{
+ //ensure we don't delete the real directory
+ QStandardPaths::setTestModeEnabled(true);
+ QDir localConfig(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation));
+ //qDebug() << "Erasing" << localConfig;
+ localConfig.removeRecursively();
+ QVERIFY(!localConfig.exists());
+}
+
+
+static QList<QByteArray> readLinesFrom(const QString& path)
+{
+ QFile file(path);
+ const bool opened = file.open(QIODevice::ReadOnly|QIODevice::Text);
+ Q_ASSERT(opened);
+ Q_UNUSED(opened);
+ QList<QByteArray> lines;
+ QByteArray line;
+ do {
+ line = file.readLine();
+ if (!line.isEmpty())
+ lines.append(line);
+ } while(!line.isEmpty());
+ return lines;
+}
+
+static QList<QByteArray> readLines(const char* fileName = "kconfigtest")
+{
+ const QString path = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + fileName;
+ Q_ASSERT(!path.isEmpty());
+ return readLinesFrom(path);
+}
+
+// see also testDefaults, which tests reverting with a defaults (global) file available
+void KConfigTest::testDirtyAfterRevert()
+{
+ KConfig sc( "kconfigtest_revert" );
+
+ KConfigGroup cg(&sc, "Hello");
+ cg.revertToDefault( "does_not_exist" );
+ QVERIFY(!sc.isDirty());
+ cg.writeEntry("Test", "Correct");
+ QVERIFY(sc.isDirty());
+ sc.sync();
+ QVERIFY(!sc.isDirty());
+
+ cg.revertToDefault("Test");
+ QVERIFY(sc.isDirty());
+ QVERIFY(sc.sync());
+ QVERIFY(!sc.isDirty());
+
+ cg.revertToDefault("Test");
+ QVERIFY(!sc.isDirty());
+}
+
+void KConfigTest::testRevertAllEntries()
+{
+ // this tests the case were we revert (delete) all entries in a file,
+ // leaving a blank file
+ {
+ KConfig sc( "konfigtest2", KConfig::SimpleConfig );
+ KConfigGroup cg( &sc, "Hello" );
+ cg.writeEntry( "Test", "Correct" );
+ }
+
+ {
+ KConfig sc( "konfigtest2", KConfig::SimpleConfig );
+ KConfigGroup cg( &sc, "Hello" );
+ QCOMPARE( cg.readEntry( "Test", "Default" ), QString("Correct") );
+ cg.revertToDefault( "Test" );
+ }
+
+ KConfig sc( "konfigtest2", KConfig::SimpleConfig );
+ KConfigGroup cg( &sc, "Hello" );
+ QCOMPARE( cg.readEntry( "Test", "Default" ), QString("Default") );
+}
+
+void KConfigTest::testSimple()
+{
+ // kdeglobals (which was created in initTestCase) must be found this way:
+ const QStringList kdeglobals = QStandardPaths::locateAll(QStandardPaths::GenericConfigLocation, QLatin1String("kdeglobals"));
+ QVERIFY(!kdeglobals.isEmpty());
+
+ KConfig sc2( "kconfigtest" );
+ QCOMPARE(sc2.name(), QString("kconfigtest"));
+
+ // make sure groupList() isn't returning something it shouldn't
+ Q_FOREACH(const QString& group, sc2.groupList()) {
+ QVERIFY(!group.isEmpty() && group != "<default>");
+ QVERIFY(!group.contains(QChar(0x1d)));
+ }
+
+ KConfigGroup sc3( &sc2, "AAA");
+
+ QVERIFY( sc3.hasKey( "stringEntry1" ) ); // from kdeglobals
+ QVERIFY( !sc3.isEntryImmutable("stringEntry1") );
+ QCOMPARE( sc3.readEntry( "stringEntry1" ), QString( STRINGENTRY1 ) );
+
+ QVERIFY( !sc3.hasKey( "stringEntry2" ) );
+ QCOMPARE( sc3.readEntry( "stringEntry2", QString("bla") ), QString( "bla" ) );
+
+ QVERIFY( !sc3.hasDefault( "stringEntry1" ) );
+
+ sc3 = KConfigGroup(&sc2, "Hello");
+ QCOMPARE( sc3.readEntry( "Test", QByteArray() ), QByteArray( UTF8BITENTRY ) );
+ QCOMPARE( sc3.readEntry( "bytearrayEntry", QByteArray() ), BYTEARRAYENTRY );
+ QCOMPARE( sc3.readEntry( ESCAPEKEY ), QString( ESCAPEENTRY ) );
+ QCOMPARE( sc3.readEntry( "Test", QString() ), QString::fromUtf8( UTF8BITENTRY ) );
+ QCOMPARE( sc3.readEntry( "emptyEntry"/*, QString("Fietsbel")*/), QString("") );
+ QCOMPARE( sc3.readEntry("emptyEntry", QString("Fietsbel")).isEmpty(), true );
+ QCOMPARE( sc3.readEntry( "stringEntry1" ), QString( STRINGENTRY1 ) );
+ QCOMPARE( sc3.readEntry( "stringEntry2" ), QString( STRINGENTRY2 ) );
+ QCOMPARE( sc3.readEntry( "stringEntry3" ), QString( STRINGENTRY3 ) );
+ QCOMPARE( sc3.readEntry( "stringEntry4" ), QString( STRINGENTRY4 ) );
+ QVERIFY( !sc3.hasKey( "stringEntry5" ) );
+ QCOMPARE( sc3.readEntry( "stringEntry5", QString("test") ), QString( "test" ) );
+ QVERIFY( !sc3.hasKey( "stringEntry6" ) );
+ QCOMPARE( sc3.readEntry( "stringEntry6", QString("foo") ), QString( "foo" ) );
+ QCOMPARE( sc3.readEntry( "urlEntry1", QUrl() ), QUrl("http://qt-project.org") );
+ QCOMPARE( sc3.readEntry( "boolEntry1", BOOLENTRY1 ), BOOLENTRY1 );
+ QCOMPARE( sc3.readEntry( "boolEntry2", false ), BOOLENTRY2 );
+ QCOMPARE( sc3.readEntry("keywith=equalsign", QString("wrong")), QString(STRINGENTRY1));
+ QCOMPARE( sc3.readEntry( "byteArrayEntry1", QByteArray() ),
+ QByteArray( STRINGENTRY1 ) );
+ QCOMPARE( sc3.readEntry( "doubleEntry1", 0.0 ), DOUBLEENTRY );
+ QCOMPARE( sc3.readEntry( "floatEntry1", 0.0f ), FLOATENTRY );
+}
+
+void KConfigTest::testDefaults()
+{
+ KConfig config("defaulttest", KConfig::NoGlobals);
+ const QString defaultsFile = "defaulttest.defaults";
+ KConfig defaults(defaultsFile, KConfig::SimpleConfig);
+
+ const QString Default("Default");
+ const QString NotDefault("Not Default");
+ const QString Value1(STRINGENTRY1);
+ const QString Value2(STRINGENTRY2);
+
+ KConfigGroup group = defaults.group("any group");
+ group.writeEntry("entry1", Default);
+ QVERIFY(group.sync());
+
+ group = config.group("any group");
+ group.writeEntry("entry1", Value1);
+ group.writeEntry("entry2", Value2);
+ QVERIFY(group.sync());
+
+ config.addConfigSources(QStringList() << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + defaultsFile);
+
+ config.setReadDefaults(true);
+ QCOMPARE(group.readEntry("entry1", QString()), Default);
+ QCOMPARE(group.readEntry("entry2", NotDefault), NotDefault); // no default for entry2
+
+ config.setReadDefaults(false);
+ QCOMPARE(group.readEntry("entry1", Default), Value1);
+ QCOMPARE(group.readEntry("entry2", NotDefault), Value2);
+
+ group.revertToDefault("entry1");
+ QCOMPARE(group.readEntry("entry1", QString()), Default);
+ group.revertToDefault("entry2");
+ QCOMPARE(group.readEntry("entry2", QString()), QString());
+
+ // TODO test reverting localized entries
+
+ Q_ASSERT(config.isDirty());
+ group.sync();
+
+ // Check that everything is OK on disk, too
+ KConfig reader("defaulttest", KConfig::NoGlobals);
+ reader.addConfigSources(QStringList() << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + defaultsFile);
+ KConfigGroup readerGroup = reader.group("any group");
+ QCOMPARE(readerGroup.readEntry("entry1", QString()), Default);
+ QCOMPARE(readerGroup.readEntry("entry2", QString()), QString());
+}
+
+void KConfigTest::testLocale()
+{
+ KConfig config("kconfigtest.locales", KConfig::SimpleConfig);
+ const QString Translated(TRANSLATEDSTRINGENTRY1);
+ const QString Untranslated(STRINGENTRY1);
+
+ KConfigGroup group = config.group("Hello");
+ group.writeEntry("stringEntry1", Untranslated);
+ config.setLocale("fr");
+ group.writeEntry("stringEntry1", Translated, KConfig::Localized|KConfig::Persistent);
+ QVERIFY(config.sync());
+
+ QCOMPARE(group.readEntry("stringEntry1", QString()), Translated);
+ QCOMPARE(group.readEntryUntranslated("stringEntry1"), Untranslated);
+
+ config.setLocale("C"); // strings written in the "C" locale are written as nonlocalized
+ group.writeEntry("stringEntry1", Untranslated, KConfig::Localized|KConfig::Persistent);
+ QVERIFY(config.sync());
+
+ QCOMPARE(group.readEntry("stringEntry1", QString()), Untranslated);
+}
+
+void KConfigTest::testEncoding()
+{
+ QString groupstr = QString::fromUtf8("UTF-8:\xc3\xb6l");
+
+ KConfig c( "kconfigtestencodings" );
+ KConfigGroup cg(&c, groupstr);
+ cg.writeEntry("key", "value");
+ QVERIFY(c.sync());
+
+ QList<QByteArray> lines = readLines("kconfigtestencodings");
+ QCOMPARE(lines.count(), 2);
+ QCOMPARE(lines.first(), QByteArray("[UTF-8:\xc3\xb6l]\n"));
+
+ KConfig c2( "kconfigtestencodings" );
+ KConfigGroup cg2(&c2, groupstr);
+ QVERIFY(cg2.readEntry("key") == QByteArray("value"));
+
+ QVERIFY(c2.groupList().contains(groupstr));
+}
+
+void KConfigTest::testLists()
+{
+ KConfig sc2( "kconfigtest" );
+ KConfigGroup sc3(&sc2, "List Types");
+
+ QCOMPARE( sc3.readEntry( QString("stringListEntry"), QStringList()),
+ STRINGLISTENTRY );
+
+ QCOMPARE( sc3.readEntry( QString("stringListEmptyEntry"), QStringList("wrong") ),
+ STRINGLISTEMPTYENTRY );
+
+ QCOMPARE( sc3.readEntry( QString("stringListJustEmptyElement"), QStringList() ),
+ STRINGLISTJUSTEMPTYELEMENT );
+
+ QCOMPARE( sc3.readEntry( QString("stringListEmptyTrailingElement"), QStringList() ),
+ STRINGLISTEMPTYTRAINLINGELEMENT );
+
+ QCOMPARE( sc3.readEntry( QString("stringListEscapeOddEntry"), QStringList()),
+ STRINGLISTESCAPEODDENTRY );
+
+ QCOMPARE( sc3.readEntry( QString("stringListEscapeEvenEntry"), QStringList()),
+ STRINGLISTESCAPEEVENENTRY );
+
+ QCOMPARE( sc3.readEntry( QString("stringListEscapeCommaEntry"), QStringList()),
+ STRINGLISTESCAPECOMMAENTRY );
+
+ QCOMPARE( sc3.readEntry( "listOfIntsEntry1" ), QString::fromLatin1( "1,2,3,4" ) );
+ QList<int> expectedIntList = INTLISTENTRY1;
+ QVERIFY( sc3.readEntry( "listOfIntsEntry1", QList<int>() ) == expectedIntList );
+
+ QCOMPARE( QVariant(sc3.readEntry( "variantListEntry", VARIANTLISTENTRY )).toStringList(),
+ QVariant(VARIANTLISTENTRY).toStringList() );
+
+ QCOMPARE( sc3.readEntry( "listOfByteArraysEntry1", QList<QByteArray>()), BYTEARRAYLISTENTRY1 );
+}
+
+void KConfigTest::testPath()
+{
+ KConfig sc2( "kconfigtest" );
+ KConfigGroup sc3(&sc2, "Path Type");
+ QCOMPARE( sc3.readPathEntry( "homepath", QString() ), HOMEPATH );
+ QCOMPARE( sc3.readPathEntry( "homepathescape", QString() ), HOMEPATHESCAPE );
+ QCOMPARE( sc3.entryMap()["homepath"], HOMEPATH );
+
+ {
+ QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/pathtest");
+ file.open(QIODevice::WriteOnly|QIODevice::Text);
+ QTextStream out(&file);
+ out.setCodec("UTF-8");
+ out << "[Test Group]" << endl
+ << "homePath=$HOME/foo" << endl
+ << "homePath2=file://$HOME/foo" << endl
+ << "withBraces[$e]=file://${HOME}/foo" << endl
+ << "URL[$e]=file://${HOME}/foo" << endl
+ << "hostname[$e]=$(hostname)" << endl
+ << "noeol=foo"; // no EOL
+ }
+ KConfig cf2("pathtest");
+ KConfigGroup group = cf2.group("Test Group");
+ QVERIFY(group.hasKey("homePath"));
+ QCOMPARE(group.readPathEntry("homePath", QString()), HOMEPATH);
+ QVERIFY(group.hasKey("homePath2"));
+ QCOMPARE(group.readPathEntry("homePath2", QString()), QString("file://" + HOMEPATH) );
+ QVERIFY(group.hasKey("withBraces"));
+ QCOMPARE(group.readPathEntry("withBraces", QString()), QString("file://" + HOMEPATH) );
+ QVERIFY(group.hasKey("URL"));
+ QCOMPARE(group.readEntry("URL", QString()), QString("file://" + HOMEPATH) );
+#if !defined(Q_OS_WIN32) && !defined(Q_OS_MAC)
+ // I don't know if this will work on windows
+ // This test hangs on OS X
+ QVERIFY(group.hasKey("hostname"));
+ char hostname[256];
+ QVERIFY(::gethostname(hostname, sizeof(hostname)) == 0);
+ QCOMPARE(group.readEntry("hostname", QString()), QString::fromLatin1(hostname));
+#endif
+ QVERIFY(group.hasKey("noeol"));
+ QCOMPARE(group.readEntry("noeol", QString()), QString("foo"));
+}
+
+void KConfigTest::testPersistenceOfExpandFlagForPath()
+{
+ // This test checks that a path entry starting with $HOME is still flagged
+ // with the expand flag after the config was altered without rewriting the
+ // path entry.
+
+ // 1st step: Open the config, add a new dummy entry and then sync the config
+ // back to the storage.
+ {
+ KConfig sc2( "kconfigtest" );
+ KConfigGroup sc3(&sc2, "Path Type");
+ sc3.writeEntry( "dummy", "dummy" );
+ QVERIFY(sc2.sync());
+ }
+
+ // 2nd step: Call testPath() again. Rewriting the config must not break
+ // the testPath() test.
+ testPath();
+}
+
+void KConfigTest::testComplex()
+{
+ KConfig sc2( "kconfigtest" );
+ KConfigGroup sc3(&sc2, "Complex Types");
+
+ QCOMPARE( sc3.readEntry( "pointEntry", QPoint() ), POINTENTRY );
+ QCOMPARE( sc3.readEntry( "sizeEntry", SIZEENTRY ), SIZEENTRY);
+ QCOMPARE( sc3.readEntry( "rectEntry", QRect(1,2,3,4) ), RECTENTRY );
+ QCOMPARE( sc3.readEntry( "dateTimeEntry", QDateTime() ).toString(Qt::ISODate),
+ DATETIMEENTRY.toString(Qt::ISODate) );
+ QCOMPARE( sc3.readEntry( "dateEntry", QDate() ).toString(Qt::ISODate),
+ DATETIMEENTRY.date().toString(Qt::ISODate) );
+ QCOMPARE( sc3.readEntry( "dateTimeEntry", QDate() ), DATETIMEENTRY.date() );
+}
+
+void KConfigTest::testEnums()
+{
+ KConfig sc("kconfigtest");
+ KConfigGroup sc3(&sc, "Enum Types" );
+
+ QCOMPARE( sc3.readEntry( "enum-10" ), QString("Tens"));
+ QVERIFY( readEntry( sc3, "enum-100", Ones) != Ones);
+ QVERIFY( readEntry( sc3, "enum-100", Ones) != Tens);
+
+ QCOMPARE( sc3.readEntry( "flags-bit0" ), QString("bit0"));
+ QVERIFY( readEntry( sc3, "flags-bit0", Flags() ) == bit0 );
+
+ int eid = staticMetaObject.indexOfEnumerator( "Flags" );
+ QVERIFY( eid != -1 );
+ QMetaEnum me = staticMetaObject.enumerator( eid );
+ Flags bitfield = bit0|bit1;
+
+ QCOMPARE( sc3.readEntry( "flags-bit0-bit1" ), QString( me.valueToKeys(bitfield) ) );
+ QVERIFY( readEntry( sc3, "flags-bit0-bit1", Flags() ) == bitfield );
+}
+
+void KConfigTest::testEntryMap()
+{
+ KConfig sc("kconfigtest");
+ KConfigGroup cg(&sc, "Hello");
+ QMap<QString, QString> entryMap = cg.entryMap();
+ qDebug() << entryMap.keys();
+ QCOMPARE(entryMap.value("stringEntry1"), QString(STRINGENTRY1));
+ QCOMPARE(entryMap.value("stringEntry2"), QString(STRINGENTRY2));
+ QCOMPARE(entryMap.value("stringEntry3"), QString(STRINGENTRY3));
+ QCOMPARE(entryMap.value("stringEntry4"), QString(STRINGENTRY4));
+ QVERIFY(!entryMap.contains("stringEntry5"));
+ QVERIFY(!entryMap.contains("stringEntry6"));
+ QCOMPARE(entryMap.value("Test"), QString::fromUtf8(UTF8BITENTRY));
+ QCOMPARE(entryMap.value("bytearrayEntry"), QString::fromUtf8(BYTEARRAYENTRY));
+ QCOMPARE(entryMap.value("emptyEntry"), QString());
+ QVERIFY(entryMap.contains("emptyEntry"));
+ QCOMPARE(entryMap.value("boolEntry1"), QString(BOOLENTRY1?"true":"false"));
+ QCOMPARE(entryMap.value("boolEntry2"), QString(BOOLENTRY2?"true":"false"));
+ QCOMPARE(entryMap.value("keywith=equalsign"), QString(STRINGENTRY1));
+ QCOMPARE(entryMap.value("byteArrayEntry1"), QString(STRINGENTRY1));
+ QCOMPARE(entryMap.value("doubleEntry1"), QString::number(DOUBLEENTRY, 'g', 15));
+ QCOMPARE(entryMap.value("floatEntry1"), QString::number(FLOATENTRY, 'g', 8));
+}
+
+void KConfigTest::testInvalid()
+{
+ KConfig sc( "kconfigtest" );
+
+ // all of these should print a message to the kdebug.dbg file
+ KConfigGroup sc3(&sc, "Invalid Types" );
+ sc3.writeEntry( "badList", VARIANTLISTENTRY2 );
+
+ QList<int> list;
+
+ // 1 element list
+ list << 1;
+ sc3.writeEntry( QString("badList"), list);
+
+ QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() );
+ QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() );
+ QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() );
+ QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() );
+ QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() );
+
+ // 2 element list
+ list << 2;
+ sc3.writeEntry( "badList", list);
+
+ QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() );
+ QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() );
+ QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() );
+
+ // 3 element list
+ list << 303;
+ sc3.writeEntry( "badList", list);
+
+ QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() );
+ QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() );
+ QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() );
+ QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() ); // out of bounds
+ QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() );
+
+ // 4 element list
+ list << 4;
+ sc3.writeEntry( "badList", list );
+
+ QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() );
+ QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() );
+ QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() );
+ QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() );
+
+ // 5 element list
+ list[2] = 3;
+ list << 5;
+ sc3.writeEntry( "badList", list);
+
+ QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() );
+ QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() );
+ QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() );
+ QVERIFY( sc3.readEntry( "badList", QDate() ) == QDate() );
+ QVERIFY( sc3.readEntry( "badList", QDateTime() ) == QDateTime() );
+
+ // 6 element list
+ list << 6;
+ sc3.writeEntry( "badList", list);
+
+ QVERIFY( sc3.readEntry( "badList", QPoint() ) == QPoint() );
+ QVERIFY( sc3.readEntry( "badList", QRect() ) == QRect() );
+ QVERIFY( sc3.readEntry( "badList", QSize() ) == QSize() );
+}
+
+void KConfigTest::testChangeGroup()
+{
+ KConfig sc( "kconfigtest" );
+ KConfigGroup sc3(&sc, "Hello");
+ QCOMPARE(sc3.name(), QString("Hello"));
+ KConfigGroup newGroup(sc3);
+#ifndef KDE_NO_DEPRECATED
+ newGroup.changeGroup("FooBar"); // deprecated!
+ QCOMPARE(newGroup.name(), QString("FooBar"));
+ QCOMPARE(sc3.name(), QString("Hello")); // unchanged
+
+ // Write into the "changed group" and check that it works
+ newGroup.writeEntry("InFooBar", "FB");
+ QCOMPARE(KConfigGroup(&sc, "FooBar").entryMap().value("InFooBar"), QString("FB"));
+ QCOMPARE(KConfigGroup(&sc, "Hello").entryMap().value("InFooBar"), QString());
+#endif
+
+ KConfigGroup rootGroup(sc.group(""));
+ QCOMPARE(rootGroup.name(), QString("<default>"));
+ KConfigGroup sc32(rootGroup.group("Hello"));
+ QCOMPARE(sc32.name(), QString("Hello"));
+ KConfigGroup newGroup2(sc32);
+#ifndef KDE_NO_DEPRECATED
+ newGroup2.changeGroup("FooBar"); // deprecated!
+ QCOMPARE(newGroup2.name(), QString("FooBar"));
+ QCOMPARE(sc32.name(), QString("Hello")); // unchanged
+#endif
+}
+
+// Simple test for deleteEntry
+void KConfigTest::testDeleteEntry()
+{
+ const char* configFile = "kconfigdeletetest";
+ {
+ KConfig conf(configFile);
+ conf.group("Hello").writeEntry("DelKey", "ToBeDeleted");
+ }
+ const QList<QByteArray> lines = readLines(configFile);
+ Q_ASSERT(lines.contains("[Hello]\n"));
+ Q_ASSERT(lines.contains("DelKey=ToBeDeleted\n"));
+
+ KConfig sc(configFile);
+ KConfigGroup group(&sc, "Hello");
+
+ group.deleteEntry("DelKey");
+ QCOMPARE( group.readEntry("DelKey", QString("Fietsbel")), QString("Fietsbel") );
+
+ QVERIFY(group.sync());
+ Q_ASSERT(!readLines(configFile).contains("DelKey=ToBeDeleted\n"));
+ QCOMPARE( group.readEntry("DelKey", QString("still deleted")), QString("still deleted") );
+}
+
+void KConfigTest::testDelete()
+{
+ KConfig sc( "kconfigtest" );
+
+ KConfigGroup ct(&sc, "Complex Types");
+
+ // First delete a nested group
+ KConfigGroup delgr(&ct, "Nested Group 3");
+ QVERIFY(delgr.exists());
+ QVERIFY(ct.hasGroup("Nested Group 3"));
+ delgr.deleteGroup();
+ QVERIFY(!delgr.exists());
+ QVERIFY(!ct.hasGroup("Nested Group 3"));
+ QVERIFY(ct.groupList().contains("Nested Group 3"));
+
+ KConfigGroup ng(&ct, "Nested Group 2");
+ QVERIFY(sc.hasGroup("Complex Types"));
+ QVERIFY(!sc.hasGroup("Does not exist"));
+ sc.deleteGroup("Complex Types");
+ QCOMPARE(sc.group("Complex Types").keyList().count(), 0);
+ QVERIFY(!sc.hasGroup("Complex Types")); // #192266
+ QVERIFY(!sc.group("Complex Types").exists());
+ QVERIFY(!ct.hasGroup("Nested Group 1"));
+
+ QCOMPARE(ct.group("Nested Group 1").keyList().count(), 0);
+ QCOMPARE(ct.group("Nested Group 2").keyList().count(), 0);
+ QCOMPARE(ng.group("Nested Group 2.1").keyList().count(), 0);
+
+ KConfigGroup cg(&sc , "AAA" );
+ cg.deleteGroup();
+ QVERIFY( sc.entryMap("Complex Types").isEmpty() );
+ QVERIFY( sc.entryMap("AAA").isEmpty() );
+ QVERIFY( !sc.entryMap("Hello").isEmpty() ); //not deleted group
+ QVERIFY( sc.entryMap("FooBar").isEmpty() ); //inexistant group
+
+ QVERIFY(cg.sync());
+ // Check what happens on disk
+ const QList<QByteArray> lines = readLines();
+ //qDebug() << lines;
+ QVERIFY(!lines.contains("[Complex Types]\n"));
+ QVERIFY(!lines.contains("[Complex Types][Nested Group 1]\n"));
+ QVERIFY(!lines.contains("[Complex Types][Nested Group 2]\n"));
+ QVERIFY(!lines.contains("[Complex Types][Nested Group 2.1]\n"));
+ QVERIFY(!lines.contains("[AAA]\n"));
+ QVERIFY(lines.contains("[Hello]\n")); // a group that was not deleted
+
+ // test for entries that are marked as deleted when there is no default
+ KConfig cf("kconfigtest", KConfig::SimpleConfig); // make sure there are no defaults
+ cg = cf.group("Portable Devices");
+ cg.writeEntry("devices|manual|(null)", "whatever");
+ cg.writeEntry("devices|manual|/mnt/ipod", "/mnt/ipod");
+ QVERIFY(cf.sync());
+
+ int count=0;
+ Q_FOREACH(const QByteArray& item, readLines())
+ if (item.startsWith("devices|")) // krazy:exclude=strings
+ count++;
+ QCOMPARE(count, 2);
+ cg.deleteEntry("devices|manual|/mnt/ipod");
+ QVERIFY(cf.sync());
+ Q_FOREACH(const QByteArray& item, readLines())
+ QVERIFY(!item.contains("ipod"));
+}
+
+void KConfigTest::testDefaultGroup()
+{
+ KConfig sc( "kconfigtest" );
+ KConfigGroup defaultGroup(&sc, "<default>");
+ QCOMPARE(defaultGroup.name(), QString("<default>"));
+ QVERIFY(!defaultGroup.exists());
+ defaultGroup.writeEntry("TestKey", "defaultGroup");
+ QVERIFY(defaultGroup.exists());
+ QCOMPARE(defaultGroup.readEntry("TestKey", QString()), QString("defaultGroup"));
+ QVERIFY(sc.sync());
+
+ {
+ // Test reading it
+ KConfig sc2("kconfigtest");
+ KConfigGroup defaultGroup2(&sc2, "<default>");
+ QCOMPARE(defaultGroup2.name(), QString("<default>"));
+ QVERIFY(defaultGroup2.exists());
+ QCOMPARE(defaultGroup2.readEntry("TestKey", QString()), QString("defaultGroup"));
+ }
+ {
+ // Test reading it
+ KConfig sc2("kconfigtest");
+ KConfigGroup emptyGroup(&sc2, "");
+ QCOMPARE(emptyGroup.name(), QString("<default>"));
+ QVERIFY(emptyGroup.exists());
+ QCOMPARE(emptyGroup.readEntry("TestKey", QString()), QString("defaultGroup"));
+ }
+
+ QList<QByteArray> lines = readLines();
+ QVERIFY(!lines.contains("[]\n"));
+ QCOMPARE(lines.first(), QByteArray("TestKey=defaultGroup\n"));
+
+ // Now that the group exists make sure it isn't returned from groupList()
+ Q_FOREACH(const QString& group, sc.groupList()) {
+ QVERIFY(!group.isEmpty() && group != "<default>");
+ }
+
+ defaultGroup.deleteGroup();
+ QVERIFY(sc.sync());
+
+ // Test if deleteGroup worked
+ lines = readLines();
+ QVERIFY(lines.first() != QByteArray("TestKey=defaultGroup\n"));
+}
+
+void KConfigTest::testEmptyGroup()
+{
+ KConfig sc( "kconfigtest" );
+ KConfigGroup emptyGroup(&sc, "");
+ QCOMPARE(emptyGroup.name(), QString("<default>")); // confusing, heh?
+ QVERIFY(!emptyGroup.exists());
+ emptyGroup.writeEntry("TestKey", "emptyGroup");
+ QVERIFY(emptyGroup.exists());
+ QCOMPARE(emptyGroup.readEntry("TestKey", QString()), QString("emptyGroup"));
+ QVERIFY(sc.sync());
+
+ {
+ // Test reading it
+ KConfig sc2("kconfigtest");
+ KConfigGroup defaultGroup(&sc2, "<default>");
+ QCOMPARE(defaultGroup.name(), QString("<default>"));
+ QVERIFY(defaultGroup.exists());
+ QCOMPARE(defaultGroup.readEntry("TestKey", QString()), QString("emptyGroup"));
+ }
+ {
+ // Test reading it
+ KConfig sc2("kconfigtest");
+ KConfigGroup emptyGroup2(&sc2, "");
+ QCOMPARE(emptyGroup2.name(), QString("<default>"));
+ QVERIFY(emptyGroup2.exists());
+ QCOMPARE(emptyGroup2.readEntry("TestKey", QString()), QString("emptyGroup"));
+ }
+
+ QList<QByteArray> lines = readLines();
+ QVERIFY(!lines.contains("[]\n")); // there's no support for the [] group, in fact.
+ QCOMPARE(lines.first(), QByteArray("TestKey=emptyGroup\n"));
+
+ // Now that the group exists make sure it isn't returned from groupList()
+ Q_FOREACH(const QString& group, sc.groupList()) {
+ QVERIFY(!group.isEmpty() && group != "<default>");
+ }
+ emptyGroup.deleteGroup();
+ QVERIFY(sc.sync());
+
+ // Test if deleteGroup worked
+ lines = readLines();
+ QVERIFY(lines.first() != QByteArray("TestKey=defaultGroup\n"));
+}
+
+void KConfigTest::testCascadingWithLocale()
+{
+ // This test relies on XDG_CONFIG_DIRS, which only has effect on Unix.
+ // Cascading (more than two levels) isn't available at all on Windows.
+#ifdef Q_OS_UNIX
+ QTemporaryDir middleDir;
+ QTemporaryDir globalDir;
+ qputenv("XDG_CONFIG_DIRS", qPrintable(middleDir.path() + QString(":") + globalDir.path()));
+
+ const QString globalConfigDir = globalDir.path();
+ QVERIFY(QDir().mkpath(globalConfigDir));
+ QFile global(globalConfigDir + "/foo.desktop");
+ QVERIFY(global.open(QIODevice::WriteOnly|QIODevice::Text));
+ QTextStream globalOut(&global);
+ globalOut << "[Group]" << endl
+ << "FromGlobal=true" << endl
+ << "FromGlobal[fr]=vrai" << endl
+ << "Name=Testing" << endl
+ << "Name[fr]=FR" << endl
+ << "Other=Global" << endl
+ << "Other[fr]=Global_FR" << endl;
+ global.close();
+
+ const QString middleConfigDir = middleDir.path();
+ QVERIFY(QDir().mkpath(middleConfigDir));
+ QFile local(middleConfigDir + "/foo.desktop");
+ QVERIFY(local.open(QIODevice::WriteOnly|QIODevice::Text));
+ QTextStream out(&local);
+ out << "[Group]" << endl
+ << "FromLocal=true" << endl
+ << "FromLocal[fr]=vrai" << endl
+ << "Name=Local Testing" << endl
+ << "Name[fr]=FR" << endl
+ << "Other=English Only" << endl;
+ local.close();
+
+ KConfig config("foo.desktop");
+ KConfigGroup group = config.group("Group");
+ QCOMPARE(group.readEntry("FromGlobal"), QString("true"));
+ QCOMPARE(group.readEntry("FromLocal"), QString("true"));
+ QCOMPARE(group.readEntry("Name"), QString("Local Testing"));
+ config.setLocale("fr");
+ QCOMPARE(group.readEntry("FromGlobal"), QString("vrai"));
+ QCOMPARE(group.readEntry("FromLocal"), QString("vrai"));
+ QCOMPARE(group.readEntry("Name"), QString("FR"));
+ QCOMPARE(group.readEntry("Other"), QString("English Only")); // Global_FR is locally overriden
+#endif
+}
+
+void KConfigTest::testMerge()
+{
+ KConfig config("mergetest", KConfig::SimpleConfig);
+
+ KConfigGroup cg = config.group("some group");
+ cg.writeEntry("entry", " random entry");
+ cg.writeEntry("another entry", "blah blah blah");
+
+ { // simulate writing by another process
+ QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/mergetest");
+ file.open(QIODevice::WriteOnly|QIODevice::Text);
+ QTextStream out(&file);
+ out.setCodec("UTF-8");
+ out << "[Merged Group]" << endl
+ << "entry1=Testing" << endl
+ << "entry2=More Testing" << endl
+ << "[some group]" << endl
+ << "entry[fr]=French" << endl
+ << "entry[es]=Spanish" << endl
+ << "entry[de]=German" << endl;
+ }
+ QVERIFY(config.sync());
+
+ {
+ QList<QByteArray> lines;
+ // this is what the file should look like
+ lines << "[Merged Group]\n"
+ << "entry1=Testing\n"
+ << "entry2=More Testing\n"
+ << "\n"
+ << "[some group]\n"
+ << "another entry=blah blah blah\n"
+ << "entry=\\srandom entry\n"
+ << "entry[de]=German\n"
+ << "entry[es]=Spanish\n"
+ << "entry[fr]=French\n";
+ QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/mergetest");
+ file.open(QIODevice::ReadOnly|QIODevice::Text);
+ Q_FOREACH (const QByteArray& line, lines) {
+ QCOMPARE(line, file.readLine());
+ }
+ }
+}
+
+void KConfigTest::testImmutable()
+{
+ {
+ QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/immutabletest");
+ file.open(QIODevice::WriteOnly|QIODevice::Text);
+ QTextStream out(&file);
+ out.setCodec("UTF-8");
+ out << "[$i]" << endl
+ << "entry1=Testing" << endl
+ << "[group][$i]" << endl
+ << "[group][subgroup][$i]" << endl;
+ }
+
+ KConfig config("immutabletest", KConfig::SimpleConfig);
+ QVERIFY(config.isGroupImmutable(QByteArray()));
+ KConfigGroup cg = config.group(QByteArray());
+ QVERIFY(cg.isEntryImmutable("entry1"));
+ KConfigGroup cg1 = config.group("group");
+ QVERIFY(cg1.isImmutable());
+ KConfigGroup cg1a = cg.group("group");
+ QVERIFY(cg1a.isImmutable());
+ KConfigGroup cg2 = cg1.group("subgroup");
+ QVERIFY(cg2.isImmutable());
+}
+
+void KConfigTest::testOptionOrder()
+{
+ {
+ QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/doubleattrtest");
+ file.open(QIODevice::WriteOnly|QIODevice::Text);
+ QTextStream out(&file);
+ out.setCodec("UTF-8");
+ out << "[group3]" << endl
+ << "entry2=unlocalized" << endl
+ << "entry2[$i][de_DE]=t2" << endl;
+ }
+ KConfig config("doubleattrtest", KConfig::SimpleConfig);
+ config.setLocale("de_DE");
+ KConfigGroup cg3 = config.group("group3");
+ QVERIFY(!cg3.isImmutable());
+ QCOMPARE(cg3.readEntry("entry2",""), QString("t2"));
+ QVERIFY(cg3.isEntryImmutable("entry2"));
+ config.setLocale("C");
+ QCOMPARE(cg3.readEntry("entry2",""), QString("unlocalized"));
+ QVERIFY(!cg3.isEntryImmutable("entry2"));
+ cg3.writeEntry("entry2","modified");
+ QVERIFY(config.sync());
+
+ {
+ QList<QByteArray> lines;
+ // this is what the file should look like
+ lines << "[group3]\n"
+ << "entry2=modified\n"
+ << "entry2[de_DE][$i]=t2\n";
+
+ QFile file(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/doubleattrtest");
+ file.open(QIODevice::ReadOnly|QIODevice::Text);
+ Q_FOREACH (const QByteArray& line, lines) {
+ QCOMPARE(line, file.readLine());
+ }
+ }
+}
+
+
+void KConfigTest::testGroupEscape()
+{
+ KConfig config("groupescapetest", KConfig::SimpleConfig);
+ QVERIFY( config.group(DOLLARGROUP).exists() );
+}
+
+void KConfigTest::testSubGroup()
+{
+ KConfig sc( "kconfigtest" );
+ KConfigGroup cg( &sc, "ParentGroup" );
+ QCOMPARE(cg.readEntry( "parentgrpstring", ""), QString("somevalue") );
+ KConfigGroup subcg1( &cg, "SubGroup1");
+ QCOMPARE(subcg1.name(), QString("SubGroup1"));
+ QCOMPARE(subcg1.readEntry( "somestring", ""), QString("somevalue") );
+ KConfigGroup subcg2( &cg, "SubGroup2");
+ QCOMPARE(subcg2.name(), QString("SubGroup2"));
+ QCOMPARE(subcg2.readEntry( "substring", ""), QString("somevalue") );
+ KConfigGroup subcg3( &cg, "SubGroup/3");
+ QCOMPARE(subcg3.readEntry( "sub3string", ""), QString("somevalue") );
+ QCOMPARE(subcg3.name(), QString("SubGroup/3"));
+ KConfigGroup rcg( &sc, "" );
+ KConfigGroup srcg( &rcg, "ParentGroup" );
+ QCOMPARE(srcg.readEntry( "parentgrpstring", ""), QString("somevalue") );
+
+ QStringList groupList = cg.groupList();
+ groupList.sort(); // comes from QSet, so order is undefined
+ QCOMPARE(groupList, (QStringList() << "SubGroup/3" << "SubGroup1" << "SubGroup2"));
+
+ const QStringList expectedSubgroup3Keys = (QStringList() << "sub3string");
+ QCOMPARE(subcg3.keyList(), expectedSubgroup3Keys);
+ const QStringList expectedParentGroupKeys(QStringList() << "parentgrpstring");
+
+ QCOMPARE(cg.keyList(), expectedParentGroupKeys);
+
+ QCOMPARE(QStringList(cg.entryMap().keys()), expectedParentGroupKeys);
+ QCOMPARE(QStringList(subcg3.entryMap().keys()), expectedSubgroup3Keys);
+
+ // Create A group containing only other groups. We want to make sure it
+ // shows up in groupList of sc
+ KConfigGroup neg(&sc, "NoEntryGroup");
+ KConfigGroup negsub1(&neg, "NEG Child1");
+ negsub1.writeEntry( "entry", "somevalue" );
+ KConfigGroup negsub2(&neg, "NEG Child2");
+ KConfigGroup negsub3(&neg, "NEG Child3");
+ KConfigGroup negsub31(&negsub3, "NEG Child3-1");
+ KConfigGroup negsub4(&neg, "NEG Child4");
+ KConfigGroup negsub41(&negsub4, "NEG Child4-1");
+ negsub41.writeEntry( "entry", "somevalue" );
+
+ // A group exists if it has content
+ QVERIFY(negsub1.exists());
+
+ // But it doesn't exist if it has no content
+ // Ossi and David say: this is how it's supposed to work.
+ // However you could add a dummy entry for now, or we could add a "Persist" feature to kconfig groups
+ // which would make it written out, much like "immutable" already makes them persistent.
+ QVERIFY(!negsub2.exists());
+
+ // A subgroup does not qualify as content if it is also empty
+ QVERIFY(!negsub3.exists());
+
+ // A subgroup with content is ok
+ QVERIFY(negsub4.exists());
+
+ // Only subgroups with content show up in groupList()
+ //QEXPECT_FAIL("", "Empty subgroups do not show up in groupList()", Continue);
+ //QCOMPARE(neg.groupList(), QStringList() << "NEG Child1" << "NEG Child2" << "NEG Child3" << "NEG Child4");
+ // This is what happens
+ QStringList groups = neg.groupList();
+ groups.sort(); // Qt5 made the ordering unreliable, due to QHash
+ QCOMPARE(groups, QStringList() << "NEG Child1" << "NEG Child4");
+
+ // make sure groupList() isn't returning something it shouldn't
+ Q_FOREACH(const QString& group, sc.groupList()) {
+ QVERIFY(!group.isEmpty() && group != "<default>");
+ QVERIFY(!group.contains(QChar(0x1d)));
+ QVERIFY(!group.contains("subgroup"));
+ QVERIFY(!group.contains("SubGroup"));
+ }
+
+ QVERIFY(sc.sync());
+
+ // Check that the empty groups are not written out.
+ const QList<QByteArray> lines = readLines();
+ QVERIFY(lines.contains("[NoEntryGroup][NEG Child1]\n"));
+ QVERIFY(!lines.contains("[NoEntryGroup][NEG Child2]\n"));
+ QVERIFY(!lines.contains("[NoEntryGroup][NEG Child3]\n"));
+ QVERIFY(!lines.contains("[NoEntryGroup][NEG Child4]\n")); // implicit group, not written out
+ QVERIFY(lines.contains("[NoEntryGroup][NEG Child4][NEG Child4-1]\n"));
+}
+
+void KConfigTest::testAddConfigSources()
+{
+ KConfig cf("specificrc");
+
+ cf.addConfigSources(QStringList() << QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/baserc");
+ cf.reparseConfiguration();
+
+ KConfigGroup specificgrp(&cf, "Specific Only Group");
+ QCOMPARE(specificgrp.readEntry("ExistingEntry", ""), QString("DevValue"));
+
+ KConfigGroup sharedgrp(&cf, "Shared Group");
+ QCOMPARE(sharedgrp.readEntry("SomeSpecificOnlyEntry",""), QString("DevValue"));
+ QCOMPARE(sharedgrp.readEntry("SomeBaseOnlyEntry",""), QString("BaseValue"));
+ QCOMPARE(sharedgrp.readEntry("SomeSharedEntry",""), QString("DevValue"));
+
+ KConfigGroup basegrp(&cf, "Base Only Group");
+ QCOMPARE(basegrp.readEntry("ExistingEntry", ""), QString("BaseValue"));
+ basegrp.writeEntry("New Entry Base Only", "SomeValue");
+
+ KConfigGroup newgrp(&cf, "New Group");
+ newgrp.writeEntry("New Entry", "SomeValue");
+
+ QVERIFY(cf.sync());
+
+ KConfig plaincfg("specificrc");
+
+ KConfigGroup newgrp2(&plaincfg, "New Group");
+ QCOMPARE(newgrp2.readEntry("New Entry", ""), QString("SomeValue"));
+
+ KConfigGroup basegrp2(&plaincfg, "Base Only Group");
+ QCOMPARE(basegrp2.readEntry("New Entry Base Only", ""), QString("SomeValue"));
+}
+
+void KConfigTest::testGroupCopyTo()
+{
+ KConfig cf1("kconfigtest");
+ KConfigGroup original = cf1.group("Enum Types");
+
+ KConfigGroup copy = cf1.group("Enum Types Copy");
+ original.copyTo(&copy); // copy from one group to another
+ QCOMPARE(copy.entryMap(), original.entryMap());
+
+ KConfig cf2("copy_of_kconfigtest", KConfig::SimpleConfig);
+ QVERIFY(!cf2.hasGroup(original.name()));
+ QVERIFY(!cf2.hasGroup(copy.name()));
+
+ KConfigGroup newGroup = cf2.group(original.name());
+ original.copyTo(&newGroup); // copy from one file to another
+ QVERIFY(cf2.hasGroup(original.name()));
+ QVERIFY(!cf2.hasGroup(copy.name())); // make sure we didn't copy more than we wanted
+ QCOMPARE(newGroup.entryMap(), original.entryMap());
+}
+
+void KConfigTest::testConfigCopyToSync()
+{
+ KConfig cf1("kconfigtest");
+ // Prepare source file
+ KConfigGroup group(&cf1, "CopyToTest");
+ group.writeEntry("Type", "Test");
+ QVERIFY(cf1.sync());
+
+ // Copy to "destination"
+ const QString destination = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigcopytotest";
+ QFile::remove(destination);
+
+ KConfig cf2("kconfigcopytotest");
+ KConfigGroup group2(&cf2, "CopyToTest");
+
+ group.copyTo(&group2);
+
+ QString testVal = group2.readEntry("Type");
+ QCOMPARE(testVal, QString("Test"));
+ // should write to disk the copied data from group
+ QVERIFY(cf2.sync());
+ QVERIFY(QFile::exists(destination));
+}
+
+void KConfigTest::testConfigCopyTo()
+{
+ KConfig cf1("kconfigtest");
+ {
+ // Prepare source file
+ KConfigGroup group(&cf1, "CopyToTest");
+ group.writeEntry("Type", "Test");
+ QVERIFY(cf1.sync());
+ }
+
+ {
+ // Copy to "destination"
+ const QString destination = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigcopytotest";
+ QFile::remove(destination);
+ KConfig cf2;
+ cf1.copyTo(destination, &cf2);
+ KConfigGroup group2(&cf2, "CopyToTest");
+ QString testVal = group2.readEntry("Type");
+ QCOMPARE(testVal, QString("Test"));
+ QVERIFY(cf2.sync());
+ QVERIFY(QFile::exists(destination));
+ }
+
+ // Check copied config file on disk
+ KConfig cf3("kconfigcopytotest");
+ KConfigGroup group3(&cf3, "CopyToTest");
+ QString testVal = group3.readEntry("Type");
+ QCOMPARE(testVal, QString("Test"));
+}
+
+void KConfigTest::testReparent()
+{
+ KConfig cf("kconfigtest");
+ const QString name("Enum Types");
+ KConfigGroup group = cf.group(name);
+ const QMap<QString, QString> originalMap = group.entryMap();
+ KConfigGroup parent = cf.group("Parent Group");
+
+ QVERIFY(!parent.hasGroup(name));
+
+ QVERIFY(group.entryMap() == originalMap);
+
+ group.reparent(&parent); // see if it can be made a sub-group of another group
+ QVERIFY(parent.hasGroup(name));
+ QCOMPARE(group.entryMap(), originalMap);
+
+ group.reparent(&cf); // see if it can make it a top-level group again
+// QVERIFY(!parent.hasGroup(name));
+ QCOMPARE(group.entryMap(), originalMap);
+}
+
+static void ageTimeStamp(const QString& path, int nsec)
+{
+#ifdef Q_OS_UNIX
+ QDateTime mtime = QFileInfo(path).lastModified().addSecs(-nsec);
+ struct utimbuf utbuf;
+ utbuf.actime = mtime.toTime_t();
+ utbuf.modtime = utbuf.actime;
+ utime(QFile::encodeName(path), &utbuf);
+#else
+ QTest::qSleep(nsec * 1000);
+#endif
+}
+
+void KConfigTest::testWriteOnSync()
+{
+ QDateTime oldStamp, newStamp;
+ KConfig sc("kconfigtest", KConfig::IncludeGlobals);
+
+ // Age the timestamp of global config file a few sec, and collect it.
+ QString globFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kdeglobals";
+ ageTimeStamp(globFile, 2); // age 2 sec
+ oldStamp = QFileInfo(globFile).lastModified();
+
+ // Add a local entry and sync the config.
+ // Should not rewrite the global config file.
+ KConfigGroup cgLocal(&sc, "Locals");
+ cgLocal.writeEntry("someLocalString", "whatever");
+ QVERIFY(sc.sync());
+
+ // Verify that the timestamp of global config file didn't change.
+ newStamp = QFileInfo(globFile).lastModified();
+ QCOMPARE(newStamp, oldStamp);
+
+ // Age the timestamp of local config file a few sec, and collect it.
+ QString locFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigtest";
+ ageTimeStamp(locFile, 2); // age 2 sec
+ oldStamp = QFileInfo(locFile).lastModified();
+
+ // Add a global entry and sync the config.
+ // Should not rewrite the local config file.
+ KConfigGroup cgGlobal(&sc, "Globals");
+ cgGlobal.writeEntry("someGlobalString", "whatever",
+ KConfig::Persistent|KConfig::Global);
+ QVERIFY(sc.sync());
+
+ // Verify that the timestamp of local config file didn't change.
+ newStamp = QFileInfo(locFile).lastModified();
+ QCOMPARE(newStamp, oldStamp);
+}
+
+void KConfigTest::testFailOnReadOnlyFileSync()
+{
+ KConfig sc("kconfigfailonreadonlytest");
+ KConfigGroup cgLocal(&sc, "Locals");
+
+ cgLocal.writeEntry("someLocalString", "whatever");
+ QVERIFY(cgLocal.sync());
+
+ QFile f(QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + '/' + sc.name());
+ QVERIFY(f.exists());
+ QVERIFY(f.setPermissions(QFileDevice::ReadOwner));
+
+ cgLocal.writeEntry("someLocalString", "whatever2");
+ QVERIFY(!cgLocal.sync());
+
+ QVERIFY(f.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner));
+ QVERIFY(f.remove());
+}
+
+void KConfigTest::testDirtyOnEqual()
+{
+ QDateTime oldStamp, newStamp;
+ KConfig sc("kconfigtest");
+
+ // Initialize value
+ KConfigGroup cgLocal(&sc, "random");
+ cgLocal.writeEntry("theKey", "whatever");
+ QVERIFY(sc.sync());
+
+ // Age the timestamp of local config file a few sec, and collect it.
+ QString locFile = QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + "/kconfigtest";
+ ageTimeStamp(locFile, 2); // age 2 sec
+ oldStamp = QFileInfo(locFile).lastModified();
+
+ // Write exactly the same again
+ cgLocal.writeEntry("theKey", "whatever");
+ // This should be a no-op
+ QVERIFY(sc.sync());
+
+ // Verify that the timestamp of local config file didn't change.
+ newStamp = QFileInfo(locFile).lastModified();
+ QCOMPARE(newStamp, oldStamp);
+}
+
+void KConfigTest::testDirtyOnEqualOverdo()
+{
+ QByteArray val1("\0""one", 4);
+ QByteArray val2("\0""two", 4);
+ QByteArray defvalr;
+
+ KConfig sc("kconfigtest");
+ KConfigGroup cgLocal(&sc, "random");
+ cgLocal.writeEntry("someKey", val1);
+ QCOMPARE(cgLocal.readEntry("someKey", defvalr), val1);
+ cgLocal.writeEntry("someKey", val2);
+ QCOMPARE(cgLocal.readEntry("someKey", defvalr), val2);
+}
+
+
+void KConfigTest::testCreateDir()
+{
+ // Test auto-creating the parent directory when needed (KConfigIniBackend::createEnclosing)
+ QString kdehome = QDir::home().canonicalPath() + "/.kde-unit-test";
+ QString subdir = kdehome + "/newsubdir";
+ QString file = subdir + "/foo.desktop";
+ QFile::remove(file);
+ QDir().rmdir(subdir);
+ QVERIFY(!QDir().exists(subdir));
+ KDesktopFile desktopFile(file);
+ desktopFile.desktopGroup().writeEntry("key", "value");
+ QVERIFY(desktopFile.sync());
+ QVERIFY(QFile::exists(file));
+
+ // Cleanup
+ QFile::remove(file);
+ QDir().rmdir(subdir);
+}
+
+void KConfigTest::testSyncOnExit()
+{
+ // Often, the KGlobalPrivate global static's destructor ends up calling ~KConfig ->
+ // KConfig::sync ... and if that code triggers KGlobal code again then things could crash.
+ // So here's a test for modifying KSharedConfig::openConfig() and not syncing, the process exit will sync.
+ KConfigGroup grp(KSharedConfig::openConfig(), "syncOnExit");
+ grp.writeEntry("key", "value");
+}
+
+void KConfigTest::testSharedConfig()
+{
+ // Can I use a KConfigGroup even after the KSharedConfigPtr goes out of scope?
+ KConfigGroup myConfigGroup;
+ {
+ KSharedConfigPtr config = KSharedConfig::openConfig("kconfigtest");
+ myConfigGroup = KConfigGroup(config, "Hello");
+ }
+ QCOMPARE(myConfigGroup.readEntry("stringEntry1"), QString(STRINGENTRY1));
+}
+
+void KConfigTest::testLocaleConfig()
+{
+ // Initialize the testdata
+ QDir dir;
+ QString subdir = QDir::home().canonicalPath() + "/.kde-unit-test/";
+ dir.mkpath(subdir);
+ QString file = subdir + "/localized.test";
+ QFile::remove(file);
+ QFile f(file);
+ QVERIFY(f.open(QIODevice::WriteOnly));
+ QTextStream ts(&f);
+ ts << "[Test_Wrong]\n";
+ ts << "foo[ca]=5\n";
+ ts << "foostring[ca]=nice\n";
+ ts << "foobool[ca]=true\n";
+ ts << "[Test_Right]\n";
+ ts << "foo=5\n";
+ ts << "foo[ca]=5\n";
+ ts << "foostring=primary\n";
+ ts << "foostring[ca]=nice\n";
+ ts << "foobool=primary\n";
+ ts << "foobool[ca]=true\n";
+ f.close();
+
+ // Load the testdata
+ QVERIFY(QFile::exists(file));
+ KConfig config(file);
+ config.setLocale("ca");
+
+ // This group has only localized values. That is not supported. The values
+ // should be dropped on loading.
+ KConfigGroup cg(&config, "Test_Wrong");
+ QEXPECT_FAIL("", "The localized values are not dropped", Continue);
+ QVERIFY(!cg.hasKey("foo"));
+ QEXPECT_FAIL("", "The localized values are not dropped", Continue);
+ QVERIFY(!cg.hasKey("foostring"));
+ QEXPECT_FAIL("", "The localized values are not dropped", Continue);
+ QVERIFY(!cg.hasKey("foobool"));
+
+ // Now check the correct config group
+ KConfigGroup cg2(&config, "Test_Right");
+ QCOMPARE(cg2.readEntry("foo"), QString("5"));
+ QCOMPARE(cg2.readEntry("foo", 3), 5);
+ QCOMPARE(cg2.readEntry("foostring"), QString("nice"));
+ QCOMPARE(cg2.readEntry("foostring", "ugly"), QString("nice"));
+ QCOMPARE(cg2.readEntry("foobool"), QString("true"));
+ QCOMPARE(cg2.readEntry("foobool", false), true);
+
+ // Clean up after the testcase
+ QFile::remove(file);
+}
+
+
+void KConfigTest::testDeleteWhenLocalized()
+{
+ // Initialize the testdata
+ QDir dir;
+ QString subdir = QDir::home().canonicalPath() + "/.kde-unit-test/";
+ dir.mkpath(subdir);
+ QString file = subdir + "/localized_delete.test";
+ QFile::remove(file);
+ QFile f(file);
+ QVERIFY(f.open(QIODevice::WriteOnly));
+ QTextStream ts(&f);
+ ts << "[Test4711]\n";
+ ts << "foo=3\n";
+ ts << "foo[ca]=5\n";
+ ts << "foo[de]=7\n";
+ ts << "foostring=ugly\n";
+ ts << "foostring[ca]=nice\n";
+ ts << "foostring[de]=schoen\n";
+ ts << "foobool=false\n";
+ ts << "foobool[ca]=true\n";
+ ts << "foobool[de]=true\n";
+ f.close();
+
+ // Load the testdata. We start in locale "ca".
+ QVERIFY(QFile::exists(file));
+ KConfig config(file);
+ config.setLocale("ca");
+ KConfigGroup cg(&config, "Test4711");
+
+ // Delete a value. Once with localized, once with Normal
+ cg.deleteEntry("foostring", KConfigBase::Persistent | KConfigBase::Localized);
+ cg.deleteEntry("foobool");
+ QVERIFY(config.sync());
+
+ // The value is now gone. The others are still there. Everything correct
+ // here.
+ QVERIFY(!cg.hasKey("foostring"));
+ QVERIFY(!cg.hasKey("foobool"));
+ QVERIFY(cg.hasKey("foo"));
+
+ // The current state is: (Just return before this comment.)
+ // [...]
+ // foobool[ca]=true
+ // foobool[de]=wahr
+ // foostring=ugly
+ // foostring[de]=schoen
+
+ // Now switch the locale to "de" and repeat the checks. Results should be
+ // the same. But they currently are not. The localized value are
+ // independent of each other. All values are still there in "de".
+ config.setLocale("de");
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foostring"));
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foobool"));
+ QVERIFY(cg.hasKey("foo"));
+ // Check where the wrong values come from.
+ // We get the "de" value.
+ QCOMPARE(cg.readEntry("foostring", "nothing"), QString("schoen"));
+ // We get the "de" value.
+ QCOMPARE(cg.readEntry("foobool", false), true);
+
+ // Now switch the locale back "ca" and repeat the checks. Results are
+ // again different.
+ config.setLocale("ca");
+ // This line worked above. But now it fails.
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foostring"));
+ // This line worked above too.
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foobool"));
+ QVERIFY(cg.hasKey("foo"));
+ // Check where the wrong values come from.
+ // We get the primary value because the "ca" value was deleted.
+ QCOMPARE(cg.readEntry("foostring", "nothing"), QString("ugly"));
+ // We get the "ca" value.
+ QCOMPARE(cg.readEntry("foobool", false), true);
+
+ // Now test the deletion of a group.
+ cg.deleteGroup();
+ QVERIFY(config.sync());
+
+ // Current state: [ca] and [de] entries left... oops.
+ //qDebug() << readLinesFrom(file);
+
+ // Bug: The group still exists [because of the localized entries]...
+ QVERIFY(cg.exists());
+ QVERIFY(!cg.hasKey("foo"));
+ QVERIFY(!cg.hasKey("foostring"));
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foobool"));
+
+ // Now switch the locale to "de" and repeat the checks. All values
+ // still here because only the primary values are deleted.
+ config.setLocale("de");
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foo"));
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foostring"));
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foobool"));
+ // Check where the wrong values come from.
+ // We get the "de" value.
+ QCOMPARE(cg.readEntry("foostring", "nothing"), QString("schoen"));
+ // We get the "de" value.
+ QCOMPARE(cg.readEntry("foobool", false), true);
+ // We get the "de" value.
+ QCOMPARE(cg.readEntry("foo", 0), 7);
+
+ // Now switch the locale to "ca" and repeat the checks
+ // "foostring" is now really gone because both the primary value and the
+ // "ca" value are deleted.
+ config.setLocale("ca");
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foo"));
+ QVERIFY(!cg.hasKey("foostring"));
+ QEXPECT_FAIL("", "Currently localized values are not deleted correctly", Continue);
+ QVERIFY(!cg.hasKey("foobool"));
+ // Check where the wrong values come from.
+ // We get the "ca" value.
+ QCOMPARE(cg.readEntry("foobool", false), true);
+ // We get the "ca" value.
+ QCOMPARE(cg.readEntry("foo", 0), 5);
+
+ // Cleanup
+ QFile::remove(file);
+}
+
+
+void KConfigTest::testKdeGlobals()
+{
+ {
+ KConfig glob("kdeglobals");
+ KConfigGroup general(&glob, "General");
+ general.writeEntry("testKG", "1");
+ QVERIFY(glob.sync());
+ }
+
+ KConfig globRead("kdeglobals");
+ const KConfigGroup general(&globRead, "General");
+ QCOMPARE(general.readEntry("testKG"), QString("1"));
+
+ // Check we wrote into kdeglobals
+ const QList<QByteArray> lines = readLines("kdeglobals");
+ QVERIFY(lines.contains("[General]\n"));
+ QVERIFY(lines.contains("testKG=1\n"));
+
+ // Writing using NoGlobals
+ {
+ KConfig glob("kdeglobals", KConfig::NoGlobals);
+ KConfigGroup general(&glob, "General");
+ general.writeEntry("testKG", "2");
+ QVERIFY(glob.sync());
+ }
+ globRead.reparseConfiguration();
+ QCOMPARE(general.readEntry("testKG"), QString("2"));
+
+ // Reading using NoGlobals
+ {
+ KConfig globReadNoGlob("kdeglobals", KConfig::NoGlobals);
+ const KConfigGroup generalNoGlob(&globReadNoGlob, "General");
+ QCOMPARE(generalNoGlob.readEntry("testKG"), QString("2"));
+ }
+
+ // TODO now use kconfigtest and writeEntry(,Global) -> should go into kdeglobals
+}
+
+void KConfigTest::testAnonymousConfig()
+{
+ KConfig anonConfig(QString(), KConfig::SimpleConfig);
+ KConfigGroup general(&anonConfig, "General");
+ QCOMPARE(general.readEntry("testKG"), QString()); // no kdeglobals merging
+ general.writeEntry("Foo", "Bar");
+ QCOMPARE(general.readEntry("Foo"), QString("Bar"));
+}
+
+#include <QThreadPool>
+#include <qtconcurrentrun.h>
+
+// To find multithreading bugs: valgrind --tool=helgrind --track-lockorders=no ./kconfigtest testThreads
+void KConfigTest::testThreads()
+{
+ QThreadPool::globalInstance()->setMaxThreadCount(6);
+ QList<QFuture<void> > futures;
+ // Run in parallel some tests that work on different config files,
+ // otherwise unexpected things might indeed happen.
+ futures << QtConcurrent::run(this, &KConfigTest::testAddConfigSources);
+ futures << QtConcurrent::run(this, &KConfigTest::testSimple);
+ futures << QtConcurrent::run(this, &KConfigTest::testDefaults);
+ // QEXPECT_FAIL triggers race conditions, it should be fixed to use QThreadStorage...
+ //futures << QtConcurrent::run(this, &KConfigTest::testDeleteWhenLocalized);
+ //futures << QtConcurrent::run(this, &KConfigTest::testEntryMap);
+ Q_FOREACH(QFuture<void> f, futures) // krazy:exclude=foreach
+ f.waitForFinished();
+}