diff options
Diffstat (limited to 'tests/auto/qsettings')
-rw-r--r-- | tests/auto/qsettings/.gitignore | 1 | ||||
-rw-r--r-- | tests/auto/qsettings/qsettings.pro | 7 | ||||
-rw-r--r-- | tests/auto/qsettings/qsettings.qrc | 9 | ||||
-rw-r--r-- | tests/auto/qsettings/resourcefile.ini | 46 | ||||
-rw-r--r-- | tests/auto/qsettings/resourcefile2.ini | 46 | ||||
-rw-r--r-- | tests/auto/qsettings/resourcefile3.ini | 50 | ||||
-rw-r--r-- | tests/auto/qsettings/resourcefile4.ini | 2 | ||||
-rw-r--r-- | tests/auto/qsettings/resourcefile5.ini | 2 | ||||
-rw-r--r-- | tests/auto/qsettings/tst_qsettings.cpp | 3808 |
9 files changed, 3971 insertions, 0 deletions
diff --git a/tests/auto/qsettings/.gitignore b/tests/auto/qsettings/.gitignore new file mode 100644 index 0000000000..090588b922 --- /dev/null +++ b/tests/auto/qsettings/.gitignore @@ -0,0 +1 @@ +tst_qsettings diff --git a/tests/auto/qsettings/qsettings.pro b/tests/auto/qsettings/qsettings.pro new file mode 100644 index 0000000000..115fb13c2b --- /dev/null +++ b/tests/auto/qsettings/qsettings.pro @@ -0,0 +1,7 @@ +load(qttest_p4) +SOURCES += tst_qsettings.cpp +RESOURCES += qsettings.qrc + +contains(QT_CONFIG, qt3support):QT += qt3support +CONFIG -= debug +CONFIG += release diff --git a/tests/auto/qsettings/qsettings.qrc b/tests/auto/qsettings/qsettings.qrc new file mode 100644 index 0000000000..587c22ebe3 --- /dev/null +++ b/tests/auto/qsettings/qsettings.qrc @@ -0,0 +1,9 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>resourcefile.ini</file> + <file>resourcefile2.ini</file> + <file>resourcefile3.ini</file> + <file>resourcefile4.ini</file> + <file>resourcefile5.ini</file> +</qresource> +</RCC> diff --git a/tests/auto/qsettings/resourcefile.ini b/tests/auto/qsettings/resourcefile.ini new file mode 100644 index 0000000000..608d1b7885 --- /dev/null +++ b/tests/auto/qsettings/resourcefile.ini @@ -0,0 +1,46 @@ +[Field%201] +Bottom=89 +Flags=MULTILINE|VSCROLL|READONLY +Left=4 +Right=296 +State=No license agreement file found. Please contact support. +Top=14 +Type=Text + +[Field%202] +Bottom=8 +Left=4 +Right=294 +Text=Press Page Down to see the rest of the agreement. +Top=0 +Type=Label + +[Field%203] +Bottom=111 +Left=4 +Right=297 +Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue. +Top=92 +Type=Label + +[Field%204] +Bottom=129 +Flags=GROUP|NOTIFY +Left=4 +Right=299 +Text=I &accept the terms in the License Agreement +Top=120 +Type=RadioButton + +[Field%205] +Bottom=140 +Flags=NOTIFY +Left=4 +Right=300 +State=1 +Text=I &do not accept the terms in the License Agreement +Top=129 +Type=RadioButton + +[Settings] +NumFields=5 diff --git a/tests/auto/qsettings/resourcefile2.ini b/tests/auto/qsettings/resourcefile2.ini new file mode 100644 index 0000000000..cd06b3b4de --- /dev/null +++ b/tests/auto/qsettings/resourcefile2.ini @@ -0,0 +1,46 @@ +[Field%202] +Flags=MULTILINE|VSCROLL|READONLY +Left=4 +Right=296 +State=No license agreement file found. Please contact support. +Bottom=89 +Top=14 +Type=Text + +[Field%201] +Left=4 +Text=Press Page Down to see the rest of the agreement. +Bottom=8 +Top=0 +Right=294 +Type=Label + +[Field%203] +Bottom=111 +Left=4 +Right=297 +Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue. +Top=92 +Type=Label + +[Field%204] +Bottom=129 +Flags=GROUP|NOTIFY +Left=4 +Right=299 +Text=I &accept the terms in the License Agreement +Top=120 +Type=RadioButton + +[Field%205] +Bottom=140 +Flags=NOTIFY +Left=4 +Right=300 +State=1 +Text=I &do not accept the terms in the License Agreement +Top=129 +Type=RadioButton + +[Settings] +NumFields=5 diff --git a/tests/auto/qsettings/resourcefile3.ini b/tests/auto/qsettings/resourcefile3.ini new file mode 100644 index 0000000000..ee54cfbbaf --- /dev/null +++ b/tests/auto/qsettings/resourcefile3.ini @@ -0,0 +1,50 @@ +[Field%202] +Flags=MULTILINE|VSCROLL|READONLY +Left=4 +Right=296 +State=No license agreement file found. Please contact support. +Bottom=89 +Top=14 +Type=Text + +[Field%201] +Left=4 +Text=Press Page Down to see the rest of the agreement. +Bottom=90 +Top=0 +Right=294 +Type=Label +x=1 +y=1 +width=1 +height=1 + +[Field%203] +Bottom=111 +Left=4 +Right=297 +Text=If you accept the terms of the agreement, select the first option below. You must accept the agreement to install this software. Click Next to continue. +Top=92 +Type=Label + +[Field%204] +Bottom=129 +Flags=GROUP|NOTIFY +Left=4 +Right=299 +Text=I &accept the terms in the License Agreement +Top=120 +Type=RadioButton + +[Field%205] +Bottom=140 +Flags=NOTIFY +Left=4 +Right=300 +State=1 +Text=I &do not accept the terms in the License Agreement +Top=129 +Type=RadioButton + +[Settings] +NumFields=5 diff --git a/tests/auto/qsettings/resourcefile4.ini b/tests/auto/qsettings/resourcefile4.ini new file mode 100644 index 0000000000..09c21b1591 --- /dev/null +++ b/tests/auto/qsettings/resourcefile4.ini @@ -0,0 +1,2 @@ +[Fa%E7ade] +QU%C9BEC=Façade/QUÉBEC diff --git a/tests/auto/qsettings/resourcefile5.ini b/tests/auto/qsettings/resourcefile5.ini new file mode 100644 index 0000000000..d2d2103560 --- /dev/null +++ b/tests/auto/qsettings/resourcefile5.ini @@ -0,0 +1,2 @@ +[Fa%E7ade] +QU%C9BEC=Façade/QUÉBEC diff --git a/tests/auto/qsettings/tst_qsettings.cpp b/tests/auto/qsettings/tst_qsettings.cpp new file mode 100644 index 0000000000..9524eb3e59 --- /dev/null +++ b/tests/auto/qsettings/tst_qsettings.cpp @@ -0,0 +1,3808 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the test suite of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#include <qdebug.h> +#include <QtTest/QtTest> + +#include <QtCore/QSettings> +#include <private/qsettings_p.h> +//#include <QtGui/QApplication> +#include <QtCore/QCoreApplication> +#include <QtCore/QtGlobal> +#include <QtCore/QMetaType> +#include <QtCore/QtDebug> +#include <QtCore/QString> + +#include <cctype> +#if defined(Q_OS_WIN) && defined(Q_CC_GNU) +// need for unlink on mingw +#include <io.h> +#endif + +#ifndef QSETTINGS_P_H_VERSION +#define QSETTINGS_P_H_VERSION 1 +#endif + +//TESTED_FILES= + +QT_FORWARD_DECLARE_CLASS(QSettings) +QT_FORWARD_DECLARE_CLASS(QSettings) + +class tst_QSettings : public QObject +{ + Q_OBJECT + +public: + tst_QSettings(); + +public slots: + void init(); + void cleanup(); +private slots: + void getSetCheck(); + void ctor_data(); + void ctor(); + void beginGroup(); + void setValue(); + void remove(); + void contains(); + void sync(); + void setFallbacksEnabled(); + void setFallbacksEnabled_data(); + void fromFile_data(); + void fromFile(); + void setIniCodec(); + void testArrays_data(); + void testArrays(); + void testEscapes(); + void testCompatFunctions(); + void testCaseSensitivity_data(); + void testCaseSensitivity(); + void testErrorHandling_data(); + void testErrorHandling(); + void testIniParsing_data(); + void testIniParsing(); + void testChildKeysAndGroups_data(); + void testChildKeysAndGroups(); + void testUpdateRequestEvent(); + void testThreadSafety(); + void testNormalizedKey_data(); + void testNormalizedKey(); + void testEmptyData(); + void testResourceFiles(); + void fileName(); + void isWritable_data(); + void isWritable(); + void childGroups_data(); + void childGroups(); + void childKeys_data(); + void childKeys(); + void allKeys_data(); + void allKeys(); + void registerFormat(); + void setPath(); + void setDefaultFormat(); + void dontCreateNeedlessPaths(); +#ifndef Q_OS_WIN + void dontReorderIniKeysNeedlessly(); +#endif + + /* + These tests were developed for the Qt 3 QSettings class. + */ +#ifdef QT3_SUPPORT + void oldWriteEntryIni_data(); + void oldWriteEntryIni(); + void oldReadEntryIni_data(); + void oldReadEntryIni(); + void oldBeginGroup_data(); + void oldBeginGroup(); + void oldEndGroup_data(); + void oldEndGroup(); + void oldResetGroup_data(); + void oldResetGroup(); + void oldEntryList_data(); + void oldEntryList(); + void oldWriteEntry_QString_bool_data(); + void oldWriteEntry_QString_bool(); + void oldWriteEntry_QString_double_data(); + void oldWriteEntry_QString_double(); + void oldWriteEntry_QString_int_data(); + void oldWriteEntry_QString_int(); + void oldWriteEntry_QString_QString_data(); + void oldWriteEntry_QString_QString(); + void oldWriteEntry_QString_QStringList_data(); + void oldWriteEntry_QString_QStringList(); + void oldWriteEntry_QString_QStringList_QChar_data(); + void oldWriteEntry_QString_QStringList_QChar(); + void oldReadListEntry_QString(); + void oldReadListEntry_QString_QChar(); + void oldReadEntry(); + void oldReadNumEntry(); + void oldReadDoubleEntry(); + void oldReadBoolEntry(); + void oldGlobalVersusLocal(); + void oldRemoveEntry(); +#endif + + void testVariantTypes_data(); + void testVariantTypes(); + void rainersSyncBugOnMac_data(); + void rainersSyncBugOnMac(); + void recursionBug(); +#ifdef QT3_SUPPORT + void setPathBug(); +#endif + + void testByteArray_data(); + void testByteArray(); + +private: + void oldWriteEntry_data(); + void oldReadEntry_data(); + void oldWriteEntryHelper(QSettings &settings); + void oldReadEntryHelper(QSettings &settings); +}; + +// Testing get/set functions +void tst_QSettings::getSetCheck() +{ + QSettings obj1; + // bool QSettings::fallbacksEnabled() + // void QSettings::setFallbacksEnabled(bool) + obj1.setFallbacksEnabled(false); + QCOMPARE(false, obj1.fallbacksEnabled()); + obj1.setFallbacksEnabled(true); + QCOMPARE(true, obj1.fallbacksEnabled()); +} + +//using namespace std; + +//#include <qapplication.h> +#include <qcoreapplication.h> +#include <qdir.h> +#include <qregexp.h> +#include <qthread.h> +#include <stdlib.h> +#ifndef Q_OS_WIN +#include <unistd.h> +#endif + +Q_DECLARE_METATYPE(QSettings::Format) + +#ifdef Q_OS_WINCE +static void removePath(const QString& _path) +{ + QString path = _path; + QDir dir(path); + if (!dir.exists()) + return; + QStringList entries = dir.entryList(); + foreach(QString name, entries) { + QString absolute = path + name; + if (QFileInfo(absolute).isDir()) + removePath(absolute+"\\"); + else + QFile::remove(absolute); + } + dir.cdUp(); + if (path[path.size()-1] == '\\') + path = path.left(path.size()-1); + dir.rmdir(path.mid(path.lastIndexOf('\\')+1)); +} +#endif + +static QString settingsPath(const char *path = "") +{ + // Temporary path for files that are specified explictly in the constructor. + QString tempPath = QDir::tempPath(); + if (tempPath.endsWith("/")) + tempPath.truncate(tempPath.size() - 1); + return QDir::toNativeSeparators(tempPath + "/tst_QSettings/" + QLatin1String(path)); +} + +#if QT_VERSION >= 0x040100 +static bool readCustom1File(QIODevice &device, QSettings::SettingsMap &map) +{ + QDataStream in(&device); + quint32 magic; + in >> magic; + in >> map; + return (magic == 0x01010101 && in.status() == QDataStream::Ok); +} + +static bool writeCustom1File(QIODevice &device, const QSettings::SettingsMap &map) +{ + QDataStream out(&device); + out << quint32(0x01010101); + out << map; + return out.status() == QDataStream::Ok; +} + +static bool readCustom2File(QIODevice &device, QSettings::SettingsMap &map) +{ + QDataStream in(&device); + quint64 magic; + in >> magic; + in >> map; + return (magic == Q_UINT64_C(0x0202020202020202) && in.status() == QDataStream::Ok); +} + +static bool writeCustom2File(QIODevice &device, const QSettings::SettingsMap &map) +{ + QDataStream out(&device); + out << Q_UINT64_C(0x0202020202020202); + out << map; + return out.status() == QDataStream::Ok; +} + +static bool readCustom3File(QIODevice &device, QSettings::SettingsMap &map) +{ + QTextStream in(&device); + QString tag; + in >> tag; + if (tag == "OK") { + map.insert("retval", "OK"); + return true; + } else { + return false; + } +} + +static bool writeCustom3File(QIODevice &device, const QSettings::SettingsMap &map) +{ + QTextStream out(&device); + if (map.value("retval") != "OK") + return false; + + out << "OK"; + return true; +} +#endif + +static void populateWithFormats() +{ + QTest::addColumn<QSettings::Format>("format"); + + QTest::newRow("native") << QSettings::NativeFormat; + QTest::newRow("ini") << QSettings::IniFormat; +#if QT_VERSION >= 0x040100 + QTest::newRow("custom1") << QSettings::CustomFormat1; + QTest::newRow("custom2") << QSettings::CustomFormat2; +#endif +} + +tst_QSettings::tst_QSettings() +{ +#if QT_VERSION >= 0x040100 + QSettings::Format custom1 = QSettings::registerFormat("custom1", readCustom1File, writeCustom1File); + QSettings::Format custom2 = QSettings::registerFormat("custom2", readCustom2File, writeCustom2File +#ifndef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER + , Qt::CaseInsensitive +#endif + ); + QVERIFY(custom1 == QSettings::CustomFormat1); + QVERIFY(custom2 == QSettings::CustomFormat2); +#endif +} + +void tst_QSettings::init() +{ + QSettings::setSystemIniPath(settingsPath("__system__")); + QSettings::setUserIniPath(settingsPath("__user__")); + +#if defined(Q_OS_WIN) + QSettings("HKEY_CURRENT_USER\\Software\\software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\other.software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\other.software.org", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\foo", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\bar", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\bat", QSettings::NativeFormat).clear(); + QSettings("HKEY_CURRENT_USER\\Software\\baz", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\foo", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\bar", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\bat", QSettings::NativeFormat).clear(); + QSettings("HKEY_LOCAL_MACHINE\\Software\\baz", QSettings::NativeFormat).clear(); + if (QDir(settingsPath()).exists()) { +#if defined(Q_OS_WINCE) + removePath(settingsPath()); +#else + if (qWinVersion() & Qt::WV_NT_based) + system(QString("rmdir /Q /S %1").arg(settingsPath()).toLatin1()); + else + system(QString("deltree /Y %1").arg(settingsPath()).toLatin1()); +#endif + } +#elif defined(Q_OS_DARWIN) + QSettings(QSettings::UserScope, "software.org", "KillerAPP").clear(); + QSettings(QSettings::SystemScope, "software.org", "KillerAPP").clear(); + QSettings(QSettings::UserScope, "other.software.org", "KillerAPP").clear(); + QSettings(QSettings::SystemScope, "other.software.org", "KillerAPP").clear(); + QSettings(QSettings::UserScope, "software.org").clear(); + QSettings(QSettings::SystemScope, "software.org").clear(); + QSettings(QSettings::UserScope, "other.software.org").clear(); + QSettings(QSettings::SystemScope, "other.software.org").clear(); +#endif + +#ifndef Q_OS_WIN + system(QString("chmod -R u+rw %1 2> /dev/null").arg(settingsPath()).toLatin1()); + system(QString("rm -fr %1 2> /dev/null").arg(settingsPath()).toLatin1()); +#endif + + QFile::remove("foo"); +} + +void tst_QSettings::cleanup() +{ + init(); +} + +/* + Test the constructors and the assignment operator. +*/ + +void tst_QSettings::ctor_data() +{ + populateWithFormats(); +} + +void tst_QSettings::ctor() +{ + QFETCH(QSettings::Format, format); + + { + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(format, QSettings::UserScope, "software.org"); + QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(format, QSettings::SystemScope, "software.org"); + + QSettings settings5(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings6(format, QSettings::UserScope, "software.org"); + QSettings settings7(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings8(format, QSettings::SystemScope, "software.org"); + + // test QSettings::format() while we're at it + QVERIFY(settings1.format() == format); + QVERIFY(settings2.format() == format); + QVERIFY(settings3.format() == format); + QVERIFY(settings4.format() == format); + + // test QSettings::scope() while we're at it + QVERIFY(settings1.scope() == QSettings::UserScope); + QVERIFY(settings2.scope() == QSettings::UserScope); + QVERIFY(settings3.scope() == QSettings::SystemScope); + QVERIFY(settings4.scope() == QSettings::SystemScope); + + // test QSettings::organizationName() while we're at it + QVERIFY(settings1.organizationName() == "software.org"); + QVERIFY(settings2.organizationName() == "software.org"); + QVERIFY(settings3.organizationName() == "software.org"); + QVERIFY(settings4.organizationName() == "software.org"); + + // test QSettings::applicationName() while we're at it + QCOMPARE(settings1.applicationName(), QString("KillerAPP")); + QVERIFY(settings2.applicationName().isEmpty()); + QVERIFY(settings3.applicationName() == "KillerAPP"); + QVERIFY(settings4.applicationName().isEmpty()); + + /* + Go forwards. + */ + settings4.setValue("key 1", QString("doodah")); + + QCOMPARE(settings1.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings3.setValue("key 1", QString("blah")); + QCOMPARE(settings1.value("key 1").toString(), QString("blah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings2.setValue("key 1", QString("whoa")); + QCOMPARE(settings1.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings1.setValue("key 1", QString("gurgle")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + /* + Test the copies. + */ + QCOMPARE(settings5.value("key 1").toString(), settings1.value("key 1").toString()); + QCOMPARE(settings6.value("key 1").toString(), settings2.value("key 1").toString()); + QCOMPARE(settings7.value("key 1").toString(), settings3.value("key 1").toString()); + QCOMPARE(settings8.value("key 1").toString(), settings4.value("key 1").toString()); + + /* + Go backwards. + */ + + settings2.setValue("key 1", QString("bilboh")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings3.setValue("key 1", QString("catha")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("catha")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings4.setValue("key 1", QString("quirko")); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("catha")); + QCOMPARE(settings4.value("key 1").toString(), QString("quirko")); + + /* + Test the copies again. + */ + QCOMPARE(settings5.value("key 1").toString(), settings1.value("key 1").toString()); + QCOMPARE(settings6.value("key 1").toString(), settings2.value("key 1").toString()); + QCOMPARE(settings7.value("key 1").toString(), settings3.value("key 1").toString()); + QCOMPARE(settings8.value("key 1").toString(), settings4.value("key 1").toString()); + + /* + "General" is a problem key for .ini files. + */ + settings1.setValue("General", 1); + settings1.setValue("%General", 2); + settings1.setValue("alpha", 3); + settings1.setValue("General/alpha", 4); + settings1.setValue("%General/alpha", 5); + settings1.setValue("alpha/General", 6); + settings1.setValue("alpha/%General", 7); + settings1.setValue("General/General", 8); + settings1.setValue("General/%General", 9); + settings1.setValue("%General/General", 10); + settings1.setValue("%General/%General", 11); + } + + { + /* + Test that the data was stored on disk after all instances + of QSettings are destroyed. + */ + + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(format, QSettings::UserScope, "software.org"); + QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(format, QSettings::SystemScope, "software.org"); + + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("bilboh")); + QCOMPARE(settings3.value("key 1").toString(), QString("catha")); + QCOMPARE(settings4.value("key 1").toString(), QString("quirko")); + + /* + Test problem keys. + */ + + QCOMPARE(settings1.value("General").toInt(), 1); + QCOMPARE(settings1.value("%General").toInt(), 2); + QCOMPARE(settings1.value("alpha").toInt(), 3); + QCOMPARE(settings1.value("General/alpha").toInt(), 4); + QCOMPARE(settings1.value("%General/alpha").toInt(), 5); + QCOMPARE(settings1.value("alpha/General").toInt(), 6); + QCOMPARE(settings1.value("alpha/%General").toInt(), 7); + QCOMPARE(settings1.value("General/General").toInt(), 8); + QCOMPARE(settings1.value("General/%General").toInt(), 9); + QCOMPARE(settings1.value("%General/General").toInt(), 10); + QCOMPARE(settings1.value("%General/%General").toInt(), 11); + + /* + Test that the organization and product parameters is + case-insensitive on Windows and Mac, case-sensitive on + Unix. + */ + QSettings settings5(format, QSettings::UserScope, "SoftWare.ORG", "killerApp"); + if (format == QSettings::NativeFormat) { +#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) + QCOMPARE(settings5.value("key 1").toString(), QString("gurgle")); +#else + QVERIFY(!settings5.contains("key 1")); +#endif + } else { +#if defined(Q_OS_WIN) || defined(Q_OS_DARWIN) + QCOMPARE(settings5.value("key 1").toString(), QString("gurgle")); +#else + QVERIFY(!settings5.contains("key 1")); +#endif + } + } + + { + QSettings settings1(settingsPath("custom/custom.conf"), QSettings::IniFormat); + settings1.beginGroup("alpha/beta"); + settings1.setValue("geometry", -7); + settings1.setValue("geometry/x", 1); + settings1.setValue("geometry/y", 2); + QSettings settings2(settingsPath("custom/custom.conf"), QSettings::IniFormat); + settings1.setValue("geometry/width", 3); + settings2.setValue("alpha/beta/geometry/height", 4); + settings2.setValue("alpha/gamma/splitter", 5); + settings1.endGroup(); + + // test QSettings::scope() while we're at it + QVERIFY(settings1.scope() == QSettings::UserScope); + + // test QSettings::organizationName() while we're at it + QVERIFY(settings1.organizationName().isEmpty()); + + // test QSettings::applicationName() while we're at it + QVERIFY(settings1.organizationName().isEmpty()); + + QSettings settings3(settingsPath("custom/custom2.conf"), QSettings::IniFormat); + settings3.beginGroup("doodley/beta"); + settings3.setValue("geometry", -7); + settings3.setValue("geometry/x", 1); + settings3.setValue("geometry/y", 2); + settings3.setValue("geometry/width", 3); + settings3.setValue("geometry/height", 4); + settings3.endGroup(); + settings3.setValue("alpha/gamma/splitter", 5); + + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 5); + QCOMPARE(settings1.allKeys().count(), 6); + + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings2.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings2.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings2.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings2.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings2.value("alpha/gamma/splitter").toInt(), 5); + QCOMPARE(settings2.allKeys().count(), 6); + } + + { + QSettings settings1(settingsPath("custom/custom.conf"), QSettings::IniFormat); + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 5); + QCOMPARE(settings1.allKeys().count(), 6); + } + + { + // QSettings's default constructor is native by default + if (format == QSettings::NativeFormat) { + QCoreApplication::instance()->setOrganizationName(""); + QCoreApplication::instance()->setApplicationName(""); + QSettings settings; + QCOMPARE(settings.status(), QSettings::AccessError); + QCoreApplication::instance()->setOrganizationName("software.org"); + QCoreApplication::instance()->setApplicationName("KillerAPP"); + QSettings settings2; + QCOMPARE(settings2.status(), QSettings::NoError); + QSettings settings3("software.org", "KillerAPP"); + QCOMPARE(settings2.fileName(), settings3.fileName()); + QCoreApplication::instance()->setOrganizationName(""); + QCoreApplication::instance()->setApplicationName(""); + } + + QSettings settings(format, QSettings::UserScope, "", ""); + QCOMPARE(settings.status(), QSettings::AccessError); + QSettings settings2(format, QSettings::UserScope, "software.org", "KillerAPP"); + QCOMPARE(settings2.status(), QSettings::NoError); + + // test QSettings::format() while we're at it + QVERIFY(settings.format() == format); + QVERIFY(settings2.format() == format); + + // test QSettings::scope() while we're at it + QVERIFY(settings.scope() == QSettings::UserScope); + QVERIFY(settings2.scope() == QSettings::UserScope); + + // test QSettings::organizationName() while we're at it + QVERIFY(settings.organizationName().isEmpty()); + QVERIFY(settings2.organizationName() == "software.org"); + + // test QSettings::applicationName() while we're at it + QVERIFY(settings.applicationName().isEmpty()); + QVERIFY(settings2.applicationName() == "KillerAPP"); + } +} + +void tst_QSettings::testByteArray_data() +{ + QTest::addColumn<QByteArray>("data"); + + QByteArray bytes("Hello world!"); + + QTest::newRow("latin1") << bytes; +#ifndef QT_NO_COMPRESS + QTest::newRow("compressed") << qCompress(bytes); +#endif + QTest::newRow("with \\0") << bytes + '\0' + bytes; +} + +void tst_QSettings::testByteArray() +{ + QFETCH(QByteArray, data); + + // write + { + QSettings settings("Trolltech", "tst_qsettings"); + settings.setValue("byteArray", data); + } + // read + { + QSettings settings("Trolltech", "tst_qsettings"); + QByteArray ret = settings.value("byteArray", data).toByteArray(); + QCOMPARE(ret, data); + } +} + +void tst_QSettings::testErrorHandling_data() +{ + QTest::addColumn<int>("filePerms"); // -1 means file should not exist + QTest::addColumn<int>("dirPerms"); + QTest::addColumn<int>("statusAfterCtor"); + QTest::addColumn<bool>("shouldBeEmpty"); + QTest::addColumn<int>("statusAfterGet"); + QTest::addColumn<int>("statusAfterSetAndSync"); + + // file dir afterCtor empty afterGet afterSetAndSync + QTest::newRow("0600 0700") << 0600 << 0700 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; + + QTest::newRow("0400 0700") << 0400 << 0700 << (int)QSettings::NoError + << false << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow("0200 0700") << 0200 << 0700 << (int)QSettings::AccessError + << true << (int)QSettings::AccessError << (int)QSettings::AccessError; + + QTest::newRow(" -1 0700") << -1 << 0700 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::NoError; + + QTest::newRow(" -1 0000") << -1 << 0000 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow(" -1 0100") << -1 << 0100 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow("0600 0100") << 0600 << 0100 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; + QTest::newRow(" -1 0300") << -1 << 0300 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::NoError; + QTest::newRow("0600 0300") << 0600 << 0300 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; + QTest::newRow(" -1 0500") << -1 << 0500 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError; + QTest::newRow("0600 0500") << 0600 << 0500 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError; +} + +void tst_QSettings::testErrorHandling() +{ +#ifdef Q_OS_WIN + QSKIP("Windows doesn't support most file modes, including read-only directories, so this test is moot.", SkipAll); +#else + QFETCH(int, filePerms); + QFETCH(int, dirPerms); + QFETCH(int, statusAfterCtor); + QFETCH(bool, shouldBeEmpty); + QFETCH(int, statusAfterGet); + QFETCH(int, statusAfterSetAndSync); + + + system(QString("chmod 700 %1 2>/dev/null").arg(settingsPath("someDir")).toLatin1()); + system(QString("chmod -R u+rwx %1 2>/dev/null").arg(settingsPath("someDir")).toLatin1()); + system(QString("rm -fr %1").arg(settingsPath("someDir")).toLatin1()); + + // prepare a file with some settings + if (filePerms != -1) { + QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat); + QCOMPARE((int) settings.status(), (int) QSettings::NoError); + + settings.beginGroup("alpha/beta"); + settings.setValue("geometry", -7); + settings.setValue("geometry/x", 1); + settings.setValue("geometry/y", 2); + settings.setValue("geometry/width", 3); + settings.setValue("geometry/height", 4); + settings.endGroup(); + settings.setValue("alpha/gamma/splitter", 5); + } else { + system(QString("mkdir -p %1").arg(settingsPath("someDir")).toLatin1()); + } + + if (filePerms != -1) { + system(QString("chmod %1 %2") + .arg(QString::number(filePerms, 8)) + .arg(settingsPath("someDir/someSettings.ini")) + .toLatin1()); + } + system(QString("chmod %1 %2") + .arg(QString::number(dirPerms, 8)) + .arg(settingsPath("someDir")) + .toLatin1()); + + // the test + { + QConfFile::clearCache(); + QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat); + QCOMPARE((int)settings.status(), statusAfterCtor); + if (shouldBeEmpty) { + QCOMPARE(settings.allKeys().count(), 0); + } else { + QVERIFY(settings.allKeys().count() > 0); + } + settings.value("alpha/beta/geometry"); + QCOMPARE((int)settings.status(), statusAfterGet); + settings.setValue("alpha/beta/geometry", 100); + QCOMPARE((int)settings.status(), statusAfterGet); + QCOMPARE(settings.value("alpha/beta/geometry").toInt(), 100); + settings.sync(); + QCOMPARE(settings.value("alpha/beta/geometry").toInt(), 100); + QCOMPARE((int)settings.status(), statusAfterSetAndSync); + } +#endif // !Q_OS_WIN +} + +Q_DECLARE_METATYPE(QVariant) +Q_DECLARE_METATYPE(QSettings::Status) + +void tst_QSettings::testIniParsing_data() +{ + QTest::addColumn<QByteArray>("inicontent"); + QTest::addColumn<QString>("key"); + QTest::addColumn<QVariant>("expect"); + QTest::addColumn<QSettings::Status>("status"); + + // Test "forgiving" parsing of entries not terminated with newline or unterminated strings + QTest::newRow("good1") << QByteArray("v=1\n") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("good2") << QByteArray("v=1\\\n2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good3") << QByteArray("v=1\\\r2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good4") << QByteArray("v=1\\\n\r2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good5") << QByteArray("v=1\\\r\n2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("good6") << QByteArray("v \t = \t 1\\\r\n2") << "v" << QVariant(12) << QSettings::NoError; + QTest::newRow("garbage1") << QByteArray("v") << "v" << QVariant() << QSettings::FormatError; + QTest::newRow("nonterm1") << QByteArray("v=str") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm2") << QByteArray("v=\"str\"") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm3") << QByteArray("v=\"str") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm4") << QByteArray("v=\\") << "v" << QVariant("") << QSettings::NoError; + QTest::newRow("nonterm5") << QByteArray("u=s\nv=\"str") << "v" << QVariant("str") << QSettings::NoError; + QTest::newRow("nonterm6") << QByteArray("v=\"str\nw=ok") << "v" << QVariant("str\nw=ok") << QSettings::NoError; + QTest::newRow("nonterm7") << QByteArray("v=") << "v" << QVariant("") << QSettings::NoError; + QTest::newRow("nonterm8") << QByteArray("v=\"str\njnk") << "v" << QVariant("str\njnk") << QSettings::NoError; + QTest::newRow("nonterm9") << QByteArray("v=1\\") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm10") << QByteArray("v=1\\\n") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm11") << QByteArray("v=1\\\r") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm12") << QByteArray("v=1\\\n\r") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm13") << QByteArray("v=1\\\r\n") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm14") << QByteArray("v=1\\\n\nx=2") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm15") << QByteArray("v=1\\\r\rx=2") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm16") << QByteArray("v=1\\\n\n\nx=2") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm17") << QByteArray("; foo\nv=1") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm18") << QByteArray("; foo\n\nv=1") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm19") << QByteArray("\nv=1;foo") << "v" << QVariant(1) << QSettings::NoError; + QTest::newRow("nonterm20") << QByteArray("v=x ") << "v" << QVariant("x") << QSettings::NoError; + QTest::newRow("nonterm21") << QByteArray("v=x ;") << "v" << QVariant("x") << QSettings::NoError; +} + +void tst_QSettings::testIniParsing() +{ + qRegisterMetaType<QVariant>("QVariant"); + qRegisterMetaType<QSettings::Status>("QSettings::Status"); + + QDir dir(settingsPath()); + QVERIFY(dir.mkpath("someDir")); + QFile f(dir.path()+"/someDir/someSettings.ini"); + + QFETCH(QByteArray, inicontent); + QFETCH(QString, key); + QFETCH(QVariant, expect); + QFETCH(QSettings::Status, status); + + QVERIFY(f.open(QFile::WriteOnly)); + f.write(inicontent); + f.close(); + + QConfFile::clearCache(); + QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat); + + if ( settings.status() == QSettings::NoError ) { // else no point proceeding + QVariant v = settings.value(key); + QVERIFY(v.canConvert(expect.type())); + // check some types so as to give prettier error messages + if ( v.type() == QVariant::String ) { + QCOMPARE(v.toString(), expect.toString()); + } else if ( v.type() == QVariant::Int ) { + QCOMPARE(v.toInt(), expect.toInt()); + } else { + QCOMPARE(v, expect); + } + } + + QCOMPARE(settings.status(), status); +} + +/* + Tests beginGroup(), endGroup(), and group(). +*/ +void tst_QSettings::beginGroup() +{ + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(QSettings::UserScope, "software.org", "KillerAPP"); + + /* + Let's start with some back and forthing. + */ + + settings1.beginGroup("alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + settings1.beginGroup("/beta"); + QCOMPARE(settings1.group(), QString("beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + + settings1.beginGroup("///gamma//"); + QCOMPARE(settings1.group(), QString("gamma")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + + settings1.setValue("geometry", 5); + QCOMPARE(settings1.value("geometry").toInt(), 5); + QCOMPARE(settings1.value("/geometry///").toInt(), 5); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("/geometry///").toInt(), 5); + + /* + OK, now start for real. + */ + + settings1.beginGroup("alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setValue("geometry", 66); + QCOMPARE(settings1.value("geometry").toInt(), 66); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + + QSettings settings3(QSettings::UserScope, "software.org", "KillerAPP"); + settings3.beginGroup("alpha"); + QCOMPARE(settings3.value("geometry").toInt(), 66); + + settings1.beginGroup("/beta///"); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.setValue("geometry", 777); + QCOMPARE(settings1.value("geometry").toInt(), 777); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings3.value("geometry").toInt(), 66); + QCOMPARE(settings3.value("beta/geometry").toInt(), 777); + + settings3.beginGroup("gamma"); + settings3.setValue("geometry", 8888); + QCOMPARE(settings3.value("geometry").toInt(), 8888); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings2.value("alpha/gamma/geometry").toInt(), 8888); + QCOMPARE(settings1.value("geometry").toInt(), 777); + + // endGroup() should do nothing if group() is empty + for (int i = 0; i < 10; ++i) + settings2.endGroup(); + QCOMPARE(settings2.value("geometry").toInt(), 5); + QCOMPARE(settings2.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings2.value("alpha/gamma/geometry").toInt(), 8888); + + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + QCOMPARE(settings1.value("geometry").toInt(), 5); + QCOMPARE(settings1.value("alpha/geometry").toInt(), 66); + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), 777); + QCOMPARE(settings1.value("alpha/gamma/geometry").toInt(), 8888); + + settings1.beginGroup("delta"); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup(""); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup("/"); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup("////"); + QCOMPARE(settings1.group(), QString("delta")); + settings1.beginGroup("////omega///epsilon zeta eta theta/ / /"); + QCOMPARE(settings1.group(), QString("delta/omega/epsilon zeta eta theta/ / ")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("delta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); +} + +/* + Tests setValue() and getXxx(). +*/ +void tst_QSettings::setValue() +{ + QSettings settings(QSettings::UserScope, "software.org", "KillerAPP"); + + settings.setValue("key 2", (int)0x7fffffff); + QCOMPARE(settings.value("key 2").toInt(), (int)0x7fffffff); + QCOMPARE(settings.value("key 2").toString(), QString::number((int)0x7fffffff)); + settings.setValue("key 2", -1); + QCOMPARE(settings.value("key 2").toInt(), -1); + QCOMPARE(settings.value("key 2").toString(), QString("-1")); + settings.setValue("key 2", (int)0x80000000); + QCOMPARE(settings.value("key 2").toInt(), (int)0x80000000); + settings.setValue("key 2", (int)0); + QCOMPARE(settings.value("key 2", 123).toInt(), (int)0); + settings.setValue("key 2", (int)12345); + QCOMPARE(settings.value("key 2").toInt(), (int)12345); + QCOMPARE(settings.value("no such key", 1234).toInt(), (int)1234); + QCOMPARE(settings.value("no such key").toInt(), (int)0); + + settings.setValue("key 2", true); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", false); + QCOMPARE(settings.value("key 2", true).toBool(), false); + settings.setValue("key 2", (int)1); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", (int)-1); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", (int)0); + QCOMPARE(settings.value("key 2", true).toBool(), false); + settings.setValue("key 2", QString("true")); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", QString("false")); + QCOMPARE(settings.value("key 2", true).toBool(), false); +/* + settings.setValue("key 2", "true"); + QCOMPARE(settings.value("key 2").toBool(), true); + settings.setValue("key 2", "false"); + QCOMPARE(settings.value("key 2", true).toBool(), false); + settings.setValue("key 2", ""); + QCOMPARE(settings.value("key 2", true).toBool(), true); + settings.setValue("key 2", ""); + QCOMPARE(settings.value("key 2", false).toBool(), false); + settings.setValue("key 2", "0.000e-00"); // cannot convert double to a bool + QCOMPARE(settings.value("key 2", true).toBool(), true); + settings.setValue("key 2", "0.000e-00"); + QCOMPARE(settings.value("key 2", false).toBool(), false); + +*/ + settings.setValue("key 2", QStringList()); + QCOMPARE(settings.value("key 2").toStringList(), QStringList()); + settings.setValue("key 2", QStringList("")); + QCOMPARE(settings.value("key 2").toStringList(), QStringList("")); + settings.setValue("key 2", QStringList() << "" << ""); + QCOMPARE(settings.value("key 2").toStringList(), QStringList() << "" << ""); + settings.setValue("key 2", QStringList() << "" << "a" << "" << "bc" << ""); + QCOMPARE(settings.value("key 2").toStringList(), QStringList() << "" << "a" << "" << "bc" << ""); + + settings.setValue("key 3", QList<QVariant>()); + QCOMPARE(settings.value("key 3").toList(), QList<QVariant>()); + settings.setValue("key 3", QList<QVariant>() << 1 << QString("a")); + QCOMPARE(settings.value("key 3").toList(), QList<QVariant>() << 1 << QString("a")); + + QList<QVariant> outerList; + outerList << 1 << QString("b"); + QList<QVariant> innerList = outerList; + outerList.append(QVariant(innerList)); + outerList.append(QVariant(innerList)); + outerList << 2 << QString("c"); + innerList = outerList; + outerList.append(QVariant(innerList)); + // outerList: [1, "b", [1, "b"], [1, "b"], 2, "c", [1, "b", [1, "b"], [1, "b"], 2, "c"]] + + settings.setValue("key 3", outerList); + QCOMPARE(settings.value("key 3").toList(), outerList); + QCOMPARE(settings.value("key 3").toList().size(), 7); + + QMap<QString, QVariant> map; + map.insert("1", "one"); + map.insert("2", "two"); + map.insert("3", outerList); + map.insert("5", "cinco"); + map.insert("10", "zehn"); + settings.setValue("key 4", map); + QCOMPARE(settings.value("key 4").toMap(), map); +} + +void tst_QSettings::testVariantTypes_data() +{ + populateWithFormats(); +} + +void tst_QSettings::testVariantTypes() +{ +#define testVal(key, val, tp, rtype) \ + { \ + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); \ + settings1.setValue(key, qVariantFromValue(val)); \ + } \ + QConfFile::clearCache(); \ + { \ + QSettings settings2(format, QSettings::UserScope, "software.org", "KillerAPP"); \ + QVariant v = settings2.value(key); \ + QVERIFY(qvariant_cast<tp >(v) == val); \ + QVERIFY(v.type() == QVariant::rtype); \ + } + + typedef QMap<QString, QVariant> TestVariantMap; + + QFETCH(QSettings::Format, format); + + TestVariantMap m2; + m2.insert("ene", "due"); + m2.insert("rike", "fake"); + m2.insert("borba", "dorba"); + testVal("key2", m2, TestVariantMap, Map); + + QStringList l2; + + l2 << "ene" << "due" << "@Point(1 2)" << "@fake"; + testVal("key3", l2, QStringList, StringList); + + l2.clear(); + l2 << "ene" << "due" << "rike" << "fake"; + testVal("key3", l2, QStringList, StringList); + + QList<QVariant> l3; + QDate date = QDate::currentDate(); + QTime time = QTime::currentTime(); + l3 << QString("ene") << 10 << qVariantFromValue(QColor(1, 2, 3)) << QVariant(QRect(1, 2, 3, 4)) + << QVariant(QSize(4, 56)) << QVariant(QPoint(4, 2)) << true << false << date << time; + testVal("key3", l3, QVariantList, List); + + testVal("key4", QString("hello"), QString, String); + testVal("key5", QColor(1, 2, 3), QColor, Color); + testVal("key6", QRect(1, 2, 3, 4), QRect, Rect); + testVal("key7", QSize(4, 56), QSize, Size); + testVal("key8", QPoint(4, 2), QPoint, Point); + testVal("key10", date, QDate, Date); + testVal("key11", time, QTime, Time); + testVal("key12", QByteArray("foo bar"), QByteArray, ByteArray); + + { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + QVERIFY(!settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + + settings.setValue("key99", QVariant()); + QVERIFY(settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + + settings.setValue("key99", QVariant(1)); + QVERIFY(settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant(1)); + + settings.setValue("key99", QVariant()); + QVERIFY(settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + + settings.remove("key99"); + QVERIFY(!settings.contains("key99")); + QCOMPARE(settings.value("key99"), QVariant()); + } + + QList<QVariant> l4; + l4 << QVariant(m2) << QVariant(l2) << QVariant(l3); + testVal("key13", l4, QVariantList, List); + + // With Qt 4.2 we store key sequences as strings instead of binary variant blob, for improved + // readability in the resulting format. + if (format >= QSettings::InvalidFormat || QT_VERSION < 0x040200) { + testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QKeySequence, KeySequence); + } else { + testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QString, String); + } + +#undef testVal +} + +void tst_QSettings::remove() +{ + QSettings settings0(QSettings::UserScope, "software.org", "KillerAPP"); + int initialNumKeys = settings0.allKeys().size(); + QCOMPARE(settings0.value("key 1", "123").toString(), QString("123")); + settings0.remove("key 1"); + QCOMPARE(settings0.value("key 1", "456").toString(), QString("456")); + + settings0.setValue("key 1", "bubloo"); + QCOMPARE(settings0.value("key 1").toString(), QString("bubloo")); + settings0.remove("key 2"); + QCOMPARE(settings0.value("key 1").toString(), QString("bubloo")); + settings0.remove("key 1"); + QCOMPARE(settings0.value("key 1", "789").toString(), QString("789")); + + /* + Make sure that removing a key removes all the subkeys. + */ + settings0.setValue("alpha/beta/geometry", -7); + settings0.setValue("alpha/beta/geometry/x", 1); + settings0.setValue("alpha/beta/geometry/y", 2); + settings0.setValue("alpha/beta/geometry/width", 3); + settings0.setValue("alpha/beta/geometry/height", 4); + settings0.setValue("alpha/gamma/splitter", 5); + + settings0.remove("alpha/beta/geometry/x"); + QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 999).toInt(), 999); + QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.remove("alpha/beta/geometry"); + QCOMPARE(settings0.value("alpha/beta/geometry", 777).toInt(), 777); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 111).toInt(), 111); + QCOMPARE(settings0.value("alpha/beta/geometry/y", 222).toInt(), 222); + QCOMPARE(settings0.value("alpha/beta/geometry/width", 333).toInt(), 333); + QCOMPARE(settings0.value("alpha/beta/geometry/height", 444).toInt(), 444); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.setValue("alpha/beta/geometry", -7); + settings0.setValue("alpha/beta/geometry/x", 1); + settings0.setValue("alpha/beta/geometry/y", 2); + settings0.setValue("alpha/beta/geometry/width", 3); + settings0.setValue("alpha/beta/geometry/height", 4); + settings0.setValue("alpha/gamma/splitter", 5); + QCOMPARE(settings0.allKeys().size(), initialNumKeys + 6); + + settings0.beginGroup("alpha/beta/geometry"); + settings0.remove(""); + settings0.endGroup(); + QVERIFY(!settings0.contains("alpha/beta/geometry")); + QVERIFY(!settings0.contains("alpha/beta/geometry/x")); + QVERIFY(!settings0.contains("alpha/beta/geometry/y")); + QVERIFY(!settings0.contains("alpha/beta/geometry/width")); + QVERIFY(!settings0.contains("alpha/beta/geometry/height")); + QVERIFY(settings0.contains("alpha/gamma/splitter")); + QCOMPARE(settings0.allKeys().size(), initialNumKeys + 1); + + settings0.beginGroup("alpha/beta"); + settings0.remove(""); + settings0.endGroup(); + QVERIFY(!settings0.contains("alpha/beta/geometry")); + QVERIFY(!settings0.contains("alpha/beta/geometry/x")); + QVERIFY(!settings0.contains("alpha/beta/geometry/y")); + QVERIFY(!settings0.contains("alpha/beta/geometry/width")); + QVERIFY(!settings0.contains("alpha/beta/geometry/height")); + QVERIFY(settings0.contains("alpha/gamma/splitter")); + QCOMPARE(settings0.allKeys().size(), initialNumKeys + 1); + + settings0.remove(""); + QVERIFY(!settings0.contains("alpha/gamma/splitter")); + QCOMPARE(settings0.allKeys().size(), initialNumKeys); + + /* + Do it again, but this time let's use setGroup(). + */ + + settings0.setValue("alpha/beta/geometry", -7); + settings0.setValue("alpha/beta/geometry/x", 1); + settings0.setValue("alpha/beta/geometry/y", 2); + settings0.setValue("alpha/beta/geometry/width", 3); + settings0.setValue("alpha/beta/geometry/height", 4); + settings0.setValue("alpha/gamma/splitter", 5); + + settings0.beginGroup("foo/bar/baz/doesn't"); + settings0.remove("exist"); + settings0.endGroup(); + QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings0.value("alpha/beta/geometry/x").toInt(), 1); + QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.beginGroup("alpha/beta/geometry"); + settings0.remove("x"); + settings0.endGroup(); + QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 999).toInt(), 999); + QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.remove("alpha/beta"); + QCOMPARE(settings0.value("alpha/beta/geometry", 777).toInt(), 777); + QCOMPARE(settings0.value("alpha/beta/geometry/x", 111).toInt(), 111); + QCOMPARE(settings0.value("alpha/beta/geometry/y", 222).toInt(), 222); + QCOMPARE(settings0.value("alpha/beta/geometry/width", 333).toInt(), 333); + QCOMPARE(settings0.value("alpha/beta/geometry/height", 444).toInt(), 444); + QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5); + + settings0.clear(); + QCOMPARE(settings0.value("alpha/gamma/splitter", 888).toInt(), 888); + + /* + OK, now let's check what happens if settings are spread across + multiple files (user vs. global, product-specific vs. + company-wide). + */ + + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(QSettings::UserScope, "software.org"); + QSettings settings3(QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(QSettings::SystemScope, "software.org"); + + settings4.setValue("key 1", "doodah"); + settings3.setValue("key 1", "blah"); + settings2.setValue("key 1", "whoa"); + settings1.setValue("key 1", "gurgle"); + QCOMPARE(settings1.value("key 1").toString(), QString("gurgle")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings1.remove("key 1"); + QCOMPARE(settings1.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings2.value("key 1").toString(), QString("whoa")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings2.remove("key 1"); + QCOMPARE(settings1.value("key 1").toString(), QString("blah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("blah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings3.remove("key 1"); + QCOMPARE(settings1.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings2.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings3.value("key 1").toString(), QString("doodah")); + QCOMPARE(settings4.value("key 1").toString(), QString("doodah")); + + settings4.remove("key 1"); + QVERIFY(!settings1.contains("key 1")); + QVERIFY(!settings2.contains("key 1")); + QVERIFY(!settings3.contains("key 1")); + QVERIFY(!settings4.contains("key 1")); + + /* + Get ready for the next part of the test. + */ + + settings1.clear(); + settings2.clear(); + settings3.clear(); + settings4.clear(); + + settings1.sync(); + settings2.sync(); + settings3.sync(); + settings4.sync(); + + /* + Check that recursive removes work correctly when some of the + keys are loaded from the file and others have been modified in + memory (corresponds to originalKeys vs. addedKeys in the + QSettingsFile code). + */ + + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/gamma/splitter", 5); + settings1.sync(); + + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + + settings1.remove("alpha/beta/geometry/y"); + QVERIFY(settings1.contains("alpha/beta/geometry")); + QVERIFY(settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(settings1.contains("alpha/beta/geometry/width")); + QVERIFY(settings1.contains("alpha/beta/geometry/height")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 5); + + settings1.remove("alpha/beta/geometry/y"); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 5); + + settings1.remove("alpha/beta/geometry/height"); + QVERIFY(settings1.contains("alpha/beta/geometry")); + QVERIFY(settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(settings1.contains("alpha/beta/geometry/width")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 4); + + settings1.remove("alpha/beta/geometry"); + QVERIFY(!settings1.contains("alpha/beta/geometry")); + QVERIFY(!settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(!settings1.contains("alpha/beta/geometry/width")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height")); + QVERIFY(settings1.contains("alpha/gamma/splitter")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 1); + + settings1.sync(); + QVERIFY(!settings1.contains("alpha/beta/geometry")); + QVERIFY(!settings1.contains("alpha/beta/geometry/x")); + QVERIFY(!settings1.contains("alpha/beta/geometry/y")); + QVERIFY(!settings1.contains("alpha/beta/geometry/width")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height")); + QVERIFY(settings1.contains("alpha/gamma/splitter")); + QCOMPARE(settings1.allKeys().size(), initialNumKeys + 1); +} + +/* + Tests contains() and keys(). +*/ +void tst_QSettings::contains() +{ + QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP"); + int initialNumKeys = settings1.allKeys().size(); // 0 on all platforms but Mac OS X. + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + settings1.setValue("alpha/gamma/splitter", 5); + settings1.setValue("alpha/gamma/splitter/ /", 5); + + QVERIFY(!settings1.contains("alpha")); + QVERIFY(!settings1.contains("alpha/beta")); + QVERIFY(!settings1.contains("///alpha///beta///")); + QVERIFY(settings1.contains("alpha/beta/geometry")); + QVERIFY(settings1.contains("///alpha///beta//geometry//")); + QVERIFY(settings1.contains("alpha/beta/geometry/x")); + QVERIFY(settings1.contains("alpha/beta/geometry/y")); + QVERIFY(settings1.contains("alpha/beta/geometry/width")); + QVERIFY(settings1.contains("alpha/beta/geometry/height")); + QVERIFY(!settings1.contains("alpha/beta/geometry/height/foo/bar/doesn't/exist")); + QVERIFY(!settings1.contains("alpha/gamma")); + QVERIFY(settings1.contains("alpha/gamma/splitter")); + QVERIFY(settings1.contains("alpha/gamma/splitter/ ")); + QVERIFY(settings1.contains("////alpha/gamma/splitter// ////")); + + settings1.beginGroup("alpha"); + QVERIFY(!settings1.contains("beta")); + QVERIFY(!settings1.contains("/////beta///")); + QVERIFY(settings1.contains("beta/geometry")); + QVERIFY(settings1.contains("/////beta//geometry//")); + QVERIFY(settings1.contains("beta/geometry/x")); + QVERIFY(settings1.contains("beta/geometry/y")); + QVERIFY(settings1.contains("beta/geometry/width")); + QVERIFY(settings1.contains("beta/geometry/height")); + QVERIFY(!settings1.contains("beta/geometry/height/foo/bar/doesn't/exist")); + QVERIFY(!settings1.contains("gamma")); + QVERIFY(settings1.contains("gamma/splitter")); + QVERIFY(settings1.contains("gamma/splitter/ ")); + QVERIFY(settings1.contains("////gamma/splitter// ////")); + + settings1.beginGroup("beta/geometry"); + QVERIFY(settings1.contains("x")); + QVERIFY(settings1.contains("y")); + QVERIFY(settings1.contains("width")); + QVERIFY(settings1.contains("height")); + QVERIFY(!settings1.contains("height/foo/bar/doesn't/exist")); + + QStringList keys = settings1.allKeys(); + QStringList expectedResult = QStringList() << "x" << "y" << "width" << "height"; + keys.sort(); + expectedResult.sort(); + int i; + QCOMPARE(keys, expectedResult); + for (i = 0; i < keys.size(); ++i) { + QVERIFY(settings1.contains(keys.at(i))); + } + + settings1.endGroup(); + QVERIFY(settings1.group() == "alpha"); + keys = settings1.allKeys(); + QCOMPARE(keys.size(), expectedResult.size() + 3); + for (i = 0; i < keys.size(); ++i) { + QVERIFY(settings1.contains(keys.at(i))); + } + + settings1.endGroup(); + QVERIFY(settings1.group().isEmpty()); + keys = settings1.allKeys(); + + QCOMPARE(keys.size(), initialNumKeys + 7); + for (i = 0; i < keys.size(); ++i) { + QVERIFY(settings1.contains(keys.at(i))); + } +} + +void tst_QSettings::sync() +{ + /* + What we're trying to test here is the case where two + instances of the same application access the same preference + files. We want to make sure that the results are 'merged', + rather than having the last application overwrite settings + set by the first application (like in Qt 3). + + This is only applicable to the INI format. The Windows + registry and Mac's CFPreferences API should take care of this + by themselves. + */ + + QSettings settings1(QSettings::IniFormat, QSettings::UserScope, "software.org"); + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + settings1.setValue("alpha/gamma/splitter", 5); + settings1.sync(); // and it all goes into the file + + QSettings settings2(QSettings::IniFormat, QSettings::UserScope, "other.software.org"); + settings2.setValue("alpha/beta/geometry/x", 8); + settings2.sync(); + + settings2.setValue("moo/beta/geometry", -7); + settings2.setValue("moo/beta/geometry/x", 1); + settings2.setValue("moo/beta/geometry/y", 2); + settings2.setValue("moo/beta/geometry/width", 3); + settings2.setValue("moo/beta/geometry/height", 4); + settings2.setValue("moo/gamma/splitter", 5); + settings2.setValue("alpha/gamma/splitter", 15); + settings2.remove("alpha/beta/geometry/x"); + settings2.remove("alpha/beta/geometry/y"); // should do nothing + + // Now "some other app" will change other.software.org.ini + QString userConfDir = settingsPath("__user__") + QDir::separator(); +#if !defined(Q_OS_WINCE) + unlink((userConfDir + "other.software.org.ini").toLatin1()); + rename((userConfDir + "software.org.ini").toLatin1(), + (userConfDir + "other.software.org.ini").toLatin1()); +#else + QFile::remove(userConfDir + "other.software.org.ini"); + QFile::rename(userConfDir + "software.org.ini" , userConfDir + "other.software.org.ini"); +#endif + + settings2.sync(); + + // And voila, we should be merged + + QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7); + QVERIFY(!settings2.contains("alpha/beta/geometry/x")); // <----- removed by settings2 + QCOMPARE(settings2.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings2.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings2.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings2.value("alpha/gamma/splitter").toInt(), 15); // <---- set by settings2 + QCOMPARE(settings2.value("moo/beta/geometry").toInt(), -7); + QCOMPARE(settings2.value("moo/beta/geometry/x").toInt(), 1); + QCOMPARE(settings2.value("moo/beta/geometry/y").toInt(), 2); + QCOMPARE(settings2.value("moo/beta/geometry/width").toInt(), 3); + QCOMPARE(settings2.value("moo/beta/geometry/height").toInt(), 4); + QCOMPARE(settings2.value("moo/gamma/splitter").toInt(), 5); + QCOMPARE(settings2.allKeys().count(), 11); + + // Now, software.org.ini no longer exists, this is same as another app + // clearing all settings. + settings1.sync(); + QCOMPARE(settings1.allKeys().count(), 0); + +/* + // Now "some other app" will change software.org.conf + unlink((userConfDir + "software.org.ini").toLatin1()); + rename((userConfDir + "other.software.org.ini").toLatin1(), + (userConfDir + "software.org.ini").toLatin1()); + + settings1.sync(); + QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 15); + QCOMPARE(settings1.value("moo/beta/geometry").toInt(), -7); + QCOMPARE(settings1.value("moo/beta/geometry/x").toInt(), 1); + QCOMPARE(settings1.value("moo/beta/geometry/y").toInt(), 2); + QCOMPARE(settings1.value("moo/beta/geometry/width").toInt(), 3); + QCOMPARE(settings1.value("moo/beta/geometry/height").toInt(), 4); + QCOMPARE(settings1.value("moo/gamma/splitter").toInt(), 5); + QCOMPARE(settings1.allKeys().count(), 11); +*/ +} + +void tst_QSettings::setFallbacksEnabled_data() +{ + populateWithFormats(); +} + +void tst_QSettings::setFallbacksEnabled() +{ + QFETCH(QSettings::Format, format); + + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(format, QSettings::UserScope, "software.org"); + QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings settings4(format, QSettings::SystemScope, "software.org"); + + settings1.setValue("key 1", "alpha"); + settings2.setValue("key 1", "beta"); + settings3.setValue("key 1", "gamma"); + settings4.setValue("key 1", "delta"); + + settings1.setValue("key 2", "alpha"); + settings2.setValue("key 2", "beta"); + settings3.setValue("key 2", "gamma"); + + settings1.setValue("key 3", "alpha"); + settings3.setValue("key 3", "gamma"); + settings4.setValue("key 3", "delta"); + + settings1.setValue("key 4", "alpha"); + settings2.setValue("key 4", "beta"); + settings4.setValue("key 4", "delta"); + + settings2.setValue("key 5", "beta"); + settings3.setValue("key 5", "gamma"); + settings4.setValue("key 5", "delta"); + + QVERIFY(settings1.fallbacksEnabled()); + QVERIFY(settings2.fallbacksEnabled()); + QVERIFY(settings3.fallbacksEnabled()); + QVERIFY(settings4.fallbacksEnabled()); + + settings1.setFallbacksEnabled(false); + settings2.setFallbacksEnabled(false); + settings3.setFallbacksEnabled(false); + settings4.setFallbacksEnabled(false); + + QVERIFY(!settings1.fallbacksEnabled()); + QVERIFY(!settings2.fallbacksEnabled()); + QVERIFY(!settings3.fallbacksEnabled()); + QVERIFY(!settings4.fallbacksEnabled()); + + /* + Make sure that the QSettings objects can still access their + main associated file when fallbacks are turned off. + */ + + QCOMPARE(settings1.value("key 1").toString(), QString("alpha")); + QCOMPARE(settings2.value("key 1").toString(), QString("beta")); + QCOMPARE(settings3.value("key 1").toString(), QString("gamma")); + QCOMPARE(settings4.value("key 1").toString(), QString("delta")); + + QCOMPARE(settings1.value("key 2").toString(), QString("alpha")); + QCOMPARE(settings2.value("key 2").toString(), QString("beta")); + QCOMPARE(settings3.value("key 2").toString(), QString("gamma")); + QVERIFY(!settings4.contains("key 2")); + + QCOMPARE(settings1.value("key 3").toString(), QString("alpha")); + QCOMPARE(settings3.value("key 3").toString(), QString("gamma")); + QCOMPARE(settings4.value("key 3").toString(), QString("delta")); + QVERIFY(!settings2.contains("key 3")); + + QCOMPARE(settings1.value("key 4").toString(), QString("alpha")); + QCOMPARE(settings2.value("key 4").toString(), QString("beta")); + QCOMPARE(settings4.value("key 4").toString(), QString("delta")); + QVERIFY(!settings3.contains("key 4")); + + QCOMPARE(settings2.value("key 5").toString(), QString("beta")); + QCOMPARE(settings3.value("key 5").toString(), QString("gamma")); + QCOMPARE(settings4.value("key 5").toString(), QString("delta")); + QVERIFY(!settings1.contains("key 5")); + + QCOMPARE(settings1.value("key 1").toString(), QString("alpha")); + QCOMPARE(settings1.value("key 5").toString(), QString("")); + QVERIFY(settings1.contains("key 1")); + QVERIFY(!settings1.contains("key 5")); +} + +void tst_QSettings::testChildKeysAndGroups_data() +{ + populateWithFormats(); +} + +void tst_QSettings::testChildKeysAndGroups() +{ + QFETCH(QSettings::Format, format); + + QSettings settings1(format, QSettings::UserScope, "software.org"); + settings1.setFallbacksEnabled(false); + settings1.setValue("alpha/beta/geometry", -7); + settings1.setValue("alpha/beta/geometry/x", 1); + settings1.setValue("alpha/beta/geometry/y", 2); + settings1.setValue("alpha/beta/geometry/width", 3); + settings1.setValue("alpha/beta/geometry/height", 4); + settings1.setValue("alpha/gamma/splitter", 5); + + QCOMPARE(settings1.childKeys(), QStringList()); + QCOMPARE(settings1.childGroups(), QStringList() << "alpha"); + + settings1.beginGroup("/alpha"); + QCOMPARE(settings1.childKeys(), QStringList()); + QCOMPARE(settings1.childGroups(), QStringList() << "beta" << "gamma"); + + settings1.beginGroup("/beta"); + QCOMPARE(settings1.childKeys(), QStringList() << "geometry"); + QCOMPARE(settings1.childGroups(), QStringList() << "geometry"); + + settings1.beginGroup("/geometry"); + QCOMPARE(settings1.childKeys(), QStringList() << "height" << "width" << "x" << "y"); + QCOMPARE(settings1.childGroups(), QStringList()); + + settings1.beginGroup("/width"); + QCOMPARE(settings1.childKeys(), QStringList()); + QCOMPARE(settings1.childGroups(), QStringList()); + + settings1.endGroup(); + settings1.endGroup(); + settings1.endGroup(); + settings1.endGroup(); + + { // task 53792 + QSettings settings2("other.software.org"); + settings2.setValue("viewbar/foo/test1", "1"); + settings2.setValue("viewbar/foo/test2", "2"); + settings2.setValue("viewbar/foo/test3", "3"); + settings2.setValue("viewbar/foo/test4", "4"); + settings2.setValue("viewbar/foo/test5", "5"); + settings2.setValue("viewbar/bar/test1", "1"); + settings2.setValue("viewbar/bar/test2", "2"); + settings2.setValue("viewbar/bar/test3", "3"); + settings2.setValue("viewbar/bar/test4", "4"); + settings2.setValue("viewbar/bar/test5", "5"); + + settings2.beginGroup("viewbar"); + QStringList l = settings2.childGroups(); + settings2.endGroup(); + l.sort(); + QCOMPARE(l, QStringList() << "bar" << "foo"); + } +} + +void tst_QSettings::testUpdateRequestEvent() +{ + QFile::remove("foo"); + QVERIFY(!QFile::exists("foo")); + + QSettings settings1("foo", QSettings::IniFormat); + QVERIFY(!QFile::exists("foo")); + QVERIFY(QFileInfo("foo").size() == 0); + settings1.setValue("key1", 1); + QVERIFY(QFileInfo("foo").size() == 0); + + qApp->processEvents(); + QVERIFY(QFileInfo("foo").size() > 0); + + settings1.remove("key1"); + QVERIFY(QFileInfo("foo").size() > 0); + + qApp->processEvents(); + QVERIFY(QFileInfo("foo").size() == 0); + + settings1.setValue("key2", 2); + QVERIFY(QFileInfo("foo").size() == 0); + + qApp->processEvents(); + QVERIFY(QFileInfo("foo").size() > 0); + + settings1.clear(); + QVERIFY(QFileInfo("foo").size() > 0); + + qApp->processEvents(); + QVERIFY(QFileInfo("foo").size() == 0); +} + +const int NumIterations = 5; +const int NumThreads = 4; + +class SettingsThread : public QThread +{ +public: + void run(); + void start(int n) { param = n; QThread::start(); } + +private: + int param; +}; + +void SettingsThread::run() +{ + for (int i = 0; i < NumIterations; ++i) { + QSettings settings("software.org", "KillerAPP"); + settings.setValue(QString::number((param * NumIterations) + i), param); + settings.sync(); + QCOMPARE((int)settings.status(), (int)QSettings::NoError); + } +} + +void tst_QSettings::testThreadSafety() +{ + SettingsThread threads[NumThreads]; + int i, j; + + for (i = 0; i < NumThreads; ++i) + threads[i].start(i + 1); + for (i = 0; i < NumThreads; ++i) + threads[i].wait(); + + QSettings settings("software.org", "KillerAPP"); + for (i = 0; i < NumThreads; ++i) { + int param = i + 1; + for (j = 0; j < NumIterations; ++j) { + QCOMPARE(settings.value(QString::number((param * NumIterations) + j)).toInt(), param); + } + } +} + +void tst_QSettings::testNormalizedKey_data() +{ + QTest::addColumn<QString>("inKey"); + QTest::addColumn<QString>("outKey"); + + QTest::newRow("empty1") << "" << ""; + QTest::newRow("empty2") << "/" << ""; + QTest::newRow("empty3") << "//" << ""; + QTest::newRow("empty4") << "///" << ""; + + QTest::newRow("a1") << "a" << "a"; + QTest::newRow("a2") << "/a" << "a"; + QTest::newRow("a3") << "a/" << "a"; + QTest::newRow("a4") << "//a" << "a"; + QTest::newRow("a5") << "a//" << "a"; + QTest::newRow("a6") << "///a" << "a"; + QTest::newRow("a7") << "a///" << "a"; + QTest::newRow("a8") << "///a/" << "a"; + QTest::newRow("a9") << "/a///" << "a"; + + QTest::newRow("ab1") << "aaa/bbb" << "aaa/bbb"; + QTest::newRow("ab2") << "/aaa/bbb" << "aaa/bbb"; + QTest::newRow("ab3") << "aaa/bbb/" << "aaa/bbb"; + QTest::newRow("ab4") << "/aaa/bbb/" << "aaa/bbb"; + QTest::newRow("ab5") << "aaa///bbb" << "aaa/bbb"; + QTest::newRow("ab6") << "aaa///bbb/" << "aaa/bbb"; + QTest::newRow("ab7") << "/aaa///bbb/" << "aaa/bbb"; + QTest::newRow("ab8") << "////aaa///bbb////" << "aaa/bbb"; +} + +void tst_QSettings::testNormalizedKey() +{ +#ifdef QTEST_REDUCED_EXPORTS + QSKIP("We can't test QSettingsPrivate on Windows", SkipAll); +#else + QFETCH(QString, inKey); + QFETCH(QString, outKey); + + inKey.detach(); + + QString result = QSettingsPrivate::normalizedKey(inKey); + QCOMPARE(result, outKey); + + /* + If the key is already normalized, we verify that outKey is + just a shallow copy of the input string. This is an important + optimization that shouldn't be removed accidentally. + */ + if (inKey == outKey) { + QVERIFY(!result.isDetached()); + } else { + if (!result.isEmpty()) { + QVERIFY(result.isDetached()); + } + } +#endif +} + +void tst_QSettings::testEmptyData() +{ + QString filename(QDir::tempPath() + "/empty.ini"); + QFile::remove(filename); + QVERIFY(!QFile::exists(filename)); + + QString nullString; + QString emptyString(""); + QStringList emptyList; + QStringList list; + QStringList list2; + + QVariantList emptyVList; + QVariantList vList, vList2, vList3; + + list << emptyString << nullString; + list2 << emptyString; + vList << emptyString; + vList2 << emptyString << nullString; + vList3 << QString("foo"); + + { + QSettings settings(filename, QSettings::IniFormat); + settings.setValue("nullString", nullString); + settings.setValue("emptyString", emptyString); + settings.setValue("emptyList", emptyList); + settings.setValue("list", list); + settings.setValue("list2", list2); + settings.setValue("emptyVList", emptyVList); + settings.setValue("vList", vList); + settings.setValue("vList2", vList2); + settings.setValue("vList3", vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + { + QSettings settings(filename, QSettings::IniFormat); + QCOMPARE(settings.value("nullString").toString(), nullString); + QCOMPARE(settings.value("emptyString").toString(), emptyString); + QCOMPARE(settings.value("emptyList").toStringList(), emptyList); + QCOMPARE(settings.value("list").toStringList(), list); + QCOMPARE(settings.value("list2").toStringList(), list2); + QCOMPARE(settings.value("emptyVList").toList(), emptyVList); + QCOMPARE(settings.value("vList").toList(), vList); + QCOMPARE(settings.value("vList2").toList(), vList2); + QCOMPARE(settings.value("vList3").toList(), vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + + { + QSettings settings("Trolltech", "tst_qsettings"); + settings.setValue("nullString", nullString); + settings.setValue("emptyString", emptyString); + settings.setValue("emptyList", emptyList); + settings.setValue("list", list); + settings.setValue("list2", list2); + settings.setValue("emptyVList", emptyVList); + settings.setValue("vList", vList); + settings.setValue("vList2", vList2); + settings.setValue("vList3", vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + { + QSettings settings("Trolltech", "tst_qsettings"); + QCOMPARE(settings.value("nullString").toString(), nullString); + QCOMPARE(settings.value("emptyString").toString(), emptyString); + QCOMPARE(settings.value("emptyList").toStringList(), emptyList); + QCOMPARE(settings.value("list").toStringList(), list); + QCOMPARE(settings.value("list2").toStringList(), list2); + QCOMPARE(settings.value("emptyVList").toList(), emptyVList); + QCOMPARE(settings.value("vList").toList(), vList); + QCOMPARE(settings.value("vList2").toList(), vList2); + QCOMPARE(settings.value("vList3").toList(), vList3); + QVERIFY(settings.status() == QSettings::NoError); + } + QFile::remove(filename); +} + +void tst_QSettings::testResourceFiles() +{ + QSettings settings(":/resourcefile.ini", QSettings::IniFormat); + QVERIFY(settings.status() == QSettings::NoError); + QVERIFY(!settings.isWritable()); + QCOMPARE(settings.value("Field 1/Bottom").toInt(), 89); + settings.setValue("Field 1/Bottom", 90); + + // the next two lines check the statu quo; another behavior would be possible + QVERIFY(settings.status() == QSettings::NoError); + QCOMPARE(settings.value("Field 1/Bottom").toInt(), 90); + + settings.sync(); + QVERIFY(settings.status() == QSettings::AccessError); + QCOMPARE(settings.value("Field 1/Bottom").toInt(), 90); +} + +void tst_QSettings::fromFile_data() +{ + populateWithFormats(); +} + +void tst_QSettings::fromFile() +{ + QFETCH(QSettings::Format, format); + + QFile::remove("foo"); + QVERIFY(!QFile::exists("foo")); + + QString path = "foo"; + +#ifdef Q_OS_WIN + if (format == QSettings::NativeFormat) + path = "\\HKEY_CURRENT_USER\\Software\\foo"; +#endif + + QStringList strList = QStringList() << "hope" << "destiny" << "chastity"; + + { + QSettings settings1(path, format); + QVERIFY(settings1.allKeys().isEmpty()); + + settings1.setValue("alpha", 1); + settings1.setValue("alpha", 2); + settings1.setValue("beta", strList); + + QSettings settings2(path, format); + QCOMPARE(settings2.value("alpha").toInt(), 2); + + settings1.sync(); +#ifndef Q_OS_WIN + QVERIFY(QFile::exists("foo")); +#endif + QCOMPARE(settings1.value("alpha").toInt(), 2); + QCOMPARE(settings2.value("alpha").toInt(), 2); + + settings2.setValue("alpha", 3); + settings2.setValue("gamma/foo.bar", 4); + QCOMPARE(settings1.value("alpha").toInt(), 3); + QCOMPARE(settings2.value("alpha").toInt(), 3); + QCOMPARE(settings1.value("beta").toStringList(), strList); + QCOMPARE(settings2.value("beta").toStringList(), strList); + QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4); + QCOMPARE(settings2.value("gamma/foo.bar").toInt(), 4); + } + + { + QSettings settings1(path, format); + QCOMPARE(settings1.value("alpha").toInt(), 3); + QCOMPARE(settings1.value("beta").toStringList(), strList); + QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4); + QCOMPARE(settings1.allKeys().size(), 3); + } +} + +void tst_QSettings::setIniCodec() +{ + QByteArray expeContents4, expeContents5; + QByteArray actualContents4, actualContents5; + + { + QFile inFile(":/resourcefile4.ini"); + inFile.open(QIODevice::ReadOnly); + expeContents4 = inFile.readAll(); + inFile.close(); + } + + { + QFile inFile(":/resourcefile5.ini"); + inFile.open(QIODevice::ReadOnly); + expeContents5 = inFile.readAll(); + inFile.close(); + } + + { + QSettings settings4(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + settings4.setIniCodec("UTF-8"); + settings4.setValue(QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"), QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC")); + settings4.sync(); + + QSettings settings5(QSettings::IniFormat, QSettings::UserScope, "other.software.org", "KillerAPP"); + settings5.setIniCodec("ISO 8859-1"); + settings5.setValue(QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"), QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC")); + settings5.sync(); + + { + QFile inFile(settings4.fileName()); + inFile.open(QIODevice::ReadOnly); + actualContents4 = inFile.readAll(); + inFile.close(); + } + + { + QFile inFile(settings5.fileName()); + inFile.open(QIODevice::ReadOnly); + actualContents5 = inFile.readAll(); + inFile.close(); + } + } + + QConfFile::clearCache(); + + QCOMPARE(actualContents4, expeContents4); + QCOMPARE(actualContents5, expeContents5); + + QSettings settings4(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + settings4.setIniCodec("UTF-8"); + QSettings settings5(QSettings::IniFormat, QSettings::UserScope, "other.software.org", "KillerAPP"); + settings5.setIniCodec("Latin-1"); + + QCOMPARE(settings4.allKeys().count(), 1); + QCOMPARE(settings5.allKeys().count(), 1); + + QCOMPARE(settings4.allKeys().first(), settings5.allKeys().first()); + QCOMPARE(settings4.value(settings4.allKeys().first()).toString(), + settings5.value(settings5.allKeys().first()).toString()); +} + +static bool containsSubList(QStringList mom, QStringList son) +{ + for (int i = 0; i < son.size(); ++i) { + if (!mom.contains(son.at(i))) + return false; + } + return true; +} + +void tst_QSettings::testArrays_data() +{ + populateWithFormats(); +} + +/* + Tests beginReadArray(), beginWriteArray(), endArray(), and + setArrayIndex(). +*/ +void tst_QSettings::testArrays() +{ + QFETCH(QSettings::Format, format); + + { + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + + settings1.beginWriteArray("foo/bar", 3); + settings1.setValue("bip", 1); + settings1.setArrayIndex(0); + settings1.setValue("ene", 2); + settings1.setValue("due", 3); + settings1.setValue("rike", 4); + settings1.setArrayIndex(1); + settings1.setValue("ene", 5); + settings1.setValue("due", 6); + settings1.setValue("rike", 7); + settings1.setArrayIndex(2); + settings1.setValue("ene", 8); + settings1.setValue("due", 9); + settings1.setValue("rike", 10); + settings1.endArray(); + + QStringList expectedList; + expectedList + << "foo/bar/bip" + << "foo/bar/size" + << "foo/bar/1/ene" + << "foo/bar/1/due" + << "foo/bar/1/rike" + << "foo/bar/2/ene" + << "foo/bar/2/due" + << "foo/bar/2/rike" + << "foo/bar/3/ene" + << "foo/bar/3/due" + << "foo/bar/3/rike"; + expectedList.sort(); + + QStringList actualList = settings1.allKeys(); + actualList.sort(); + QVERIFY(containsSubList(actualList, expectedList)); + + QCOMPARE(settings1.value("/foo/bar/bip").toInt(), 1); + QCOMPARE(settings1.value("/foo/bar/1/ene").toInt(), 2); + QCOMPARE(settings1.value("/foo/bar/1/due").toInt(), 3); + QCOMPARE(settings1.value("/foo/bar/1/rike").toInt(), 4); + QCOMPARE(settings1.value("/foo/bar/2/ene").toInt(), 5); + QCOMPARE(settings1.value("/foo/bar/2/due").toInt(), 6); + QCOMPARE(settings1.value("/foo/bar/2/rike").toInt(), 7); + QCOMPARE(settings1.value("/foo/bar/3/ene").toInt(), 8); + QCOMPARE(settings1.value("/foo/bar/3/due").toInt(), 9); + QCOMPARE(settings1.value("/foo/bar/3/rike").toInt(), 10); + + settings1.beginGroup("/foo"); + int count = settings1.beginReadArray("bar"); + QCOMPARE(count, 3); + QCOMPARE(settings1.value("bip").toInt(), 1); + settings1.setArrayIndex(0); + QCOMPARE(settings1.value("ene").toInt(), 2); + QCOMPARE(settings1.value("due").toInt(), 3); + QCOMPARE(settings1.value("rike").toInt(), 4); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(1); + QCOMPARE(settings1.value("ene").toInt(), 5); + QCOMPARE(settings1.value("due").toInt(), 6); + QCOMPARE(settings1.value("rike").toInt(), 7); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(2); + QCOMPARE(settings1.value("ene").toInt(), 8); + QCOMPARE(settings1.value("due").toInt(), 9); + QCOMPARE(settings1.value("rike").toInt(), 10); + QCOMPARE(settings1.allKeys().count(), 3); + + settings1.endArray(); + settings1.endGroup(); + } + /* + Check that we get the arrays right when we load them again + */ + + { + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + + QStringList expectedList; + expectedList + << "foo/bar/bip" + << "foo/bar/size" + << "foo/bar/1/ene" + << "foo/bar/1/due" + << "foo/bar/1/rike" + << "foo/bar/2/ene" + << "foo/bar/2/due" + << "foo/bar/2/rike" + << "foo/bar/3/ene" + << "foo/bar/3/due" + << "foo/bar/3/rike"; + expectedList.sort(); + + QStringList actualList = settings1.allKeys(); + actualList.sort(); + QVERIFY(containsSubList(actualList, expectedList)); + + QCOMPARE(settings1.value("/foo/bar/bip").toInt(), 1); + QCOMPARE(settings1.value("/foo/bar/1/ene").toInt(), 2); + QCOMPARE(settings1.value("/foo/bar/1/due").toInt(), 3); + QCOMPARE(settings1.value("/foo/bar/1/rike").toInt(), 4); + QCOMPARE(settings1.value("/foo/bar/2/ene").toInt(), 5); + QCOMPARE(settings1.value("/foo/bar/2/due").toInt(), 6); + QCOMPARE(settings1.value("/foo/bar/2/rike").toInt(), 7); + QCOMPARE(settings1.value("/foo/bar/3/ene").toInt(), 8); + QCOMPARE(settings1.value("/foo/bar/3/due").toInt(), 9); + QCOMPARE(settings1.value("/foo/bar/3/rike").toInt(), 10); + + settings1.beginGroup("/foo"); + int count = settings1.beginReadArray("bar"); + QCOMPARE(count, 3); + QCOMPARE(settings1.value("bip").toInt(), 1); + settings1.setArrayIndex(0); + QCOMPARE(settings1.value("ene").toInt(), 2); + QCOMPARE(settings1.value("due").toInt(), 3); + QCOMPARE(settings1.value("rike").toInt(), 4); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(1); + QCOMPARE(settings1.value("ene").toInt(), 5); + QCOMPARE(settings1.value("due").toInt(), 6); + QCOMPARE(settings1.value("rike").toInt(), 7); + QCOMPARE(settings1.allKeys().count(), 3); + settings1.setArrayIndex(2); + QCOMPARE(settings1.value("ene").toInt(), 8); + QCOMPARE(settings1.value("due").toInt(), 9); + QCOMPARE(settings1.value("rike").toInt(), 10); + QCOMPARE(settings1.allKeys().count(), 3); + + settings1.endArray(); + settings1.endGroup(); + } + /* + This code generates lots of warnings, but that's on purpose. + Basically, we check that endGroup() can be used instead of + endArray() and vice versa. This is not documented, but this + is the behavior that we have chosen. + */ + QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); + settings1.clear(); + settings1.beginGroup("/alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setArrayIndex(0); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setArrayIndex(1); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.setArrayIndex(2); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.beginGroup("/beta"); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.beginGroup(""); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.beginWriteArray("DO", 4); + QCOMPARE(settings1.value("size").toInt(), 4); + QCOMPARE(settings1.group(), QString("alpha/beta/DO")); + settings1.setArrayIndex(0); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/1")); + settings1.setArrayIndex(1); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2")); + settings1.beginGroup("1"); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.setArrayIndex(3); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.setArrayIndex(4); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.beginWriteArray("RE"); + QVERIFY(!settings1.contains("size")); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE")); + settings1.setArrayIndex(0); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE/1")); + settings1.setArrayIndex(1); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE/2")); + settings1.endArray(); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1")); + settings1.endArray(); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/2")); + settings1.setArrayIndex(2); + QCOMPARE(settings1.group(), QString("alpha/beta/DO/3")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha/beta")); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString("alpha")); + settings1.endArray(); + QCOMPARE(settings1.group(), QString()); + settings1.endGroup(); + QCOMPARE(settings1.group(), QString()); + + /* + Now, let's make sure that things work well if an array + is spread across multiple files. + */ + int i; + + settings1.clear(); + QSettings settings2(format, QSettings::UserScope, "software.org"); + + QStringList threeStrings; + threeStrings << "Uno" << "Dos" << "Tres"; + + QStringList fiveStrings; + fiveStrings << "alpha" << "beta" << "gamma" << "delta" << "epsilon"; + + settings1.beginWriteArray("strings"); + for (i = threeStrings.size() - 1; i >= 0; --i) { + settings1.setArrayIndex(i); + settings1.setValue("fileName", threeStrings.at(i)); + } + settings1.endArray(); + + settings2.beginWriteArray("strings"); + for (i = fiveStrings.size() - 1; i >= 0; --i) { + settings2.setArrayIndex(i); + settings2.setValue("fileName", fiveStrings.at(i)); + } + settings2.endArray(); + + int size1 = settings1.beginReadArray("strings"); + QCOMPARE(size1, 3); + QCOMPARE(settings1.value("size").toInt(), 3); + + for (i = 0; i < size1; ++i) { + settings1.setArrayIndex(i); + QString str = settings1.value("fileName").toString(); + QCOMPARE(str, threeStrings.at(i)); + } + settings1.endArray(); + + int size2 = settings2.beginReadArray("strings"); + QCOMPARE(size2, 5); + QCOMPARE(settings2.value("size").toInt(), 5); + + for (i = 0; i < size2; ++i) { + settings2.setArrayIndex(i); + QString str = settings2.value("fileName").toString(); + QCOMPARE(str, fiveStrings.at(i)); + } + settings2.endArray(); + + size1 = settings1.beginReadArray("strings"); + QCOMPARE(size1, 3); + + // accessing entries beyond the end of settings1 goes to settings2 + for (i = size1; i < size2; ++i) { + settings1.setArrayIndex(i); + QString str = settings1.value("fileName").toString(); + QCOMPARE(str, fiveStrings.at(i)); + } + settings1.endArray(); +} + +static QByteArray iniEscapedKey(const QString &str) +{ + QByteArray result; + QSettingsPrivate::iniEscapedKey(str, result); + return result; +} + +static QString iniUnescapedKey(const QByteArray &ba) +{ + QString result; + QSettingsPrivate::iniUnescapedKey(ba, 0, ba.size(), result); + return result; +} + +static QByteArray iniEscapedStringList(const QStringList &strList) +{ + QByteArray result; + QSettingsPrivate::iniEscapedStringList(strList, result, 0); + return result; +} + +static QStringList iniUnescapedStringList(const QByteArray &ba) +{ + QStringList result; + QString str; +#if QSETTINGS_P_H_VERSION >= 2 + bool isStringList = QSettingsPrivate::iniUnescapedStringList(ba, 0, ba.size(), str, result +#if QSETTINGS_P_H_VERSION >= 3 + , 0 +#endif + ); + if (!isStringList) + result = QStringList(str); +#else + QStringList *strList = QSettingsPrivate::iniUnescapedStringList(ba, 0, ba.size(), str); + if (strList) { + result = *strList; + delete strList; + } else { + result = QStringList(str); + } +#endif + return result; +} + +QString escapeWeirdChars(const QString &s) +{ + QString result; + bool escapeNextDigit = false; + + for (int i = 0; i < s.length(); ++i) { + QChar c = s.at(i); + if (c.unicode() < ' ' || c.unicode() > '~' + || (escapeNextDigit && c.unicode() >= '0' && c.unicode() <= 'f')) { + result += QString("\\x%1").arg(c.unicode(), 0, 16); + escapeNextDigit = true; + } else { + result += c; + escapeNextDigit = false; + } + } + + return result; +} + +void tst_QSettings::testEscapes() +{ + QSettings settings(QSettings::UserScope, "software.org", "KillerAPP"); + +#define testEscapedKey(plainKey, escKey) \ + QCOMPARE(iniEscapedKey(plainKey), QByteArray(escKey)); \ + QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); + +#define testUnescapedKey(escKey, plainKey, reescKey) \ + QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); \ + QCOMPARE(iniEscapedKey(plainKey), QByteArray(reescKey)); \ + QCOMPARE(iniUnescapedKey(reescKey), QString(plainKey)); + +#define testEscapedStringList(plainStrList, escStrList) \ + { \ + QStringList plainList(plainStrList); \ + QByteArray escList(escStrList); \ + QCOMPARE(iniEscapedStringList(plainList), escList); \ + QCOMPARE(iniUnescapedStringList(escList), plainList); \ + } \ + + +#define testUnescapedStringList(escStrList, plainStrList, reescStrList) \ + { \ + QStringList plainList(plainStrList); \ + QByteArray escList(escStrList); \ + QByteArray reescList(reescStrList); \ + QCOMPARE(iniUnescapedStringList(escList), plainList); \ + QCOMPARE(iniEscapedStringList(plainList), reescList); \ + QCOMPARE(iniUnescapedStringList(reescList), plainList); \ + } \ + + +#define testVariant(val, escStr, func) \ + { \ + QVariant v(val); \ + QString s = QSettingsPrivate::variantToString(v); \ + /*qDebug() << QString("testVariant(): reference=\"%1\" result=\"%2\"").arg(escStr).arg(s); */\ + QCOMPARE(s, escStr); \ + QCOMPARE(QVariant(QSettingsPrivate::stringToVariant(escStr)), v); \ + QVERIFY(val == v.func()); \ + } + +#define testBadEscape(escStr, vStr) \ + { \ + QVariant v = QSettingsPrivate::stringToVariant(QString(escStr)); \ + QCOMPARE(v.toString(), QString(vStr)); \ + } + + testEscapedKey("", ""); + testEscapedKey(" ", "%20"); + testEscapedKey(" 0123 abcd ", "%200123%20abcd%20"); + testEscapedKey("~!@#$%^&*()_+.-/\\=", "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D"); + testEscapedKey(QString() + QChar(0xabcd) + QChar(0x1234) + QChar(0x0081), "%UABCD%U1234%81"); + testEscapedKey(QString() + QChar(0xFE) + QChar(0xFF) + QChar(0x100) + QChar(0x101), "%FE%FF%U0100%U0101"); + + testUnescapedKey("", "", ""); + testUnescapedKey("%20", " ", "%20"); + testUnescapedKey("/alpha/beta", "/alpha/beta", "\\alpha\\beta"); + testUnescapedKey("\\alpha\\beta", "/alpha/beta", "\\alpha\\beta"); + testUnescapedKey("%5Calpha%5Cbeta", "\\alpha\\beta", "%5Calpha%5Cbeta"); + testUnescapedKey("%", "%", "%25"); + testUnescapedKey("%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%", QString("%f%!%%%%1x%x1%U%Uz%U123") + QChar(0x1234) + "\x12" + "34%", + "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25"); + + testEscapedStringList("", ""); + testEscapedStringList(" ", "\" \""); + testEscapedStringList(";", "\";\""); + testEscapedStringList(",", "\",\""); + testEscapedStringList("=", "\"=\""); + testEscapedStringList("abc-def", "abc-def"); + testEscapedStringList(QChar(0) + QString("0"), "\\0\\x30"); + testEscapedStringList("~!@#$%^&*()_+.-/\\=", "\"~!@#$%^&*()_+.-/\\\\=\""); + testEscapedStringList("~!@#$%^&*()_+.-/\\", "~!@#$%^&*()_+.-/\\\\"); + testEscapedStringList(QString("\x7F") + "12aFz", "\\x7f\\x31\\x32\\x61\\x46z"); + testEscapedStringList(QString(" \t\n\\n") + QChar(0x123) + QChar(0x4567), "\" \\t\\n\\\\n\\x123\\x4567\""); + testEscapedStringList(QString("\a\b\f\n\r\t\v'\"?\001\002\x03\x04"), "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4"); + testEscapedStringList(QStringList() << "," << ";" << "a" << "ab, \tc, d ", "\",\", \";\", a, \"ab, \\tc, d \""); + + /* + Test .ini syntax that cannot be generated by QSettings (but can be entered by users). + */ + testUnescapedStringList("", "", ""); + testUnescapedStringList("\"\"", "", ""); + testUnescapedStringList("\"abcdef\"", "abcdef", "abcdef"); + testUnescapedStringList("\"\\?\\'\\\"\"", "?'\"", "?'\\\""); + testUnescapedStringList("\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\", + QString() + QChar(0) + QChar(0) + QChar(0) + QChar(0) + QChar(1) + + QChar(0111) + QChar(011111) + QChar(0) + QChar(0xCDEF) + "GH" + + QChar(0x3456), + "\\0\\0\\0\\0\\x1I\\x1249\\0\\xcdefGH\\x3456"); + testUnescapedStringList(QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16), "\f", "\\f"); + testUnescapedStringList("\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,", + QStringList() << "a" << "bc " << " d" << "ef " << "" << "g" << "hi i" + << "" << "" << "" << "", + "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , "); + testUnescapedStringList("a , b , c d , efg ", + QStringList() << "a" << "b" << "c d" << "efg", + "a, b, c d, efg"); + + // streaming qvariant into a string + testVariant(QString("Hello World!"), QString("Hello World!"), toString); + testVariant(QString("Hello, World!"), QString("Hello, World!"), toString); + testVariant(QString("@Hello World!"), QString("@@Hello World!"), toString); + testVariant(QString("@@Hello World!"), QString("@@@Hello World!"), toString); + testVariant(QByteArray("Hello World!"), QString("@ByteArray(Hello World!)"), toString); + testVariant(QByteArray("@Hello World!"), QString("@ByteArray(@Hello World!)"), toString); + testVariant(QVariant(100), QString("100"), toString); + testVariant(QStringList() << "ene" << "due" << "rike", QString::fromLatin1("@Variant(\x0\x0\x0\xb\x0\x0\x0\x3\x0\x0\x0\x6\x0\x65\x0n\x0\x65\x0\x0\x0\x6\x0\x64\x0u\x0\x65\x0\x0\x0\x8\x0r\x0i\x0k\x0\x65)", 50), toStringList); + testVariant(QRect(1, 2, 3, 4), QString("@Rect(1 2 3 4)"), toRect); + testVariant(QSize(5, 6), QString("@Size(5 6)"), toSize); + testVariant(QPoint(7, 8), QString("@Point(7 8)"), toPoint); + + testBadEscape("", ""); + testBadEscape("@", "@"); + testBadEscape("@@", "@"); + testBadEscape("@@@", "@@"); + testBadEscape(" ", " "); + testBadEscape("@Rect", "@Rect"); + testBadEscape("@Rect(", "@Rect("); + testBadEscape("@Rect()", "@Rect()"); + testBadEscape("@Rect)", "@Rect)"); + testBadEscape("@Rect(1 2 3)", "@Rect(1 2 3)"); + testBadEscape("@@Rect(1 2 3)", "@Rect(1 2 3)"); +} + +void tst_QSettings::testCompatFunctions() +{ +#ifdef QT3_SUPPORT + QSettings settings1("software.org", "KillerAPP"); + + bool ok; + ok = settings1.writeEntry("/root/bool", true); + QVERIFY(ok); + ok = settings1.writeEntry("/root/double", 1.4); + QVERIFY(ok); + ok = settings1.writeEntry("/root/int", 66666); + QVERIFY(ok); + ok = settings1.writeEntry("/root/const char */1", "Hello"); + QVERIFY(ok); + ok = settings1.writeEntry("/root/const char */2", ""); + QVERIFY(ok); + ok = settings1.writeEntry("/root/const char */3", (const char *)0); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QString/1", QString("Hello")); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QString/2", QString("")); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QString/3", QString()); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QStringList/1", QStringList()); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QStringList/2", QStringList() << ""); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QStringList/3", QStringList() << "a" << "" << "b"); + QVERIFY(ok); + ok = settings1.writeEntry("/root/QStringList/4", QStringList() << "a" << "" << "b", ':'); + QVERIFY(ok); + + QCOMPARE(settings1.readBoolEntry("/root/bool"), true); + QCOMPARE(settings1.readDoubleEntry("/root/double"), 1.4); + QCOMPARE(settings1.readNumEntry("/root/int"), 66666); + QCOMPARE(settings1.readEntry("/root/const char */1"), QString("Hello")); + QCOMPARE(settings1.readEntry("/root/const char */2"), QString("")); + QCOMPARE(settings1.readEntry("/root/const char */3"), QString()); + QCOMPARE(settings1.readEntry("/root/QString/1"), QString("Hello")); + QCOMPARE(settings1.readEntry("/root/QString/2"), QString("")); + QCOMPARE(settings1.readEntry("/root/QString/3"), QString()); + QCOMPARE(settings1.readListEntry("/root/QStringList/1"), QStringList()); + QCOMPARE(settings1.readListEntry("/root/QStringList/2"), QStringList() << ""); + QCOMPARE(settings1.readListEntry("/root/QStringList/3"), QStringList() << "a" << "" << "b"); + QCOMPARE(settings1.readListEntry("/root/QStringList/4", ':'), QStringList() << "a" << "" << "b"); + QCOMPARE(settings1.readEntry("/root/QStringList/4"), QString("a::b")); + + QStringList actual, expectedSubKey, expectedEntry; + + settings1.clear(); + QStringList initialKeys = settings1.allKeys(); + settings1.setValue("/alpha/beta", 5); + settings1.setValue("/alpha/beta/gamma", 5); + settings1.setValue("/alpha/beta/delta", 5); + settings1.setValue("/alpha/epsilon/zeta/eta", 5); + settings1.setValue("/alpha/theta", 5); + + settings1.beginGroup("/alpha"); + QCOMPARE(settings1.group(), QString("alpha")); + + actual = settings1.entryList(""); + actual.sort(); + expectedEntry = QStringList() << "beta" << "theta"; + QCOMPARE(actual, expectedEntry); + + actual = settings1.subkeyList(""); + actual.sort(); + expectedSubKey = QStringList() << "beta" << "epsilon"; + QCOMPARE(actual, expectedSubKey); + + settings1.endGroup(); + + actual = settings1.entryList("alpha"); + actual.sort(); + QCOMPARE(actual, expectedEntry); + + actual = settings1.subkeyList("alpha"); + actual.sort(); + QCOMPARE(actual, expectedSubKey); + + actual = settings1.entryList(""); + QVERIFY(containsSubList(initialKeys, actual)); + + actual = settings1.subkeyList(""); + QVERIFY(actual.contains("alpha")); + + actual = settings1.subkeyList("foo/bar/baz"); + QVERIFY(actual.isEmpty()); + + actual = settings1.subkeyList("alpha/epsilon"); + expectedSubKey = QStringList() << "zeta"; + QCOMPARE(actual, expectedSubKey); +#else + QSKIP("Compiled without Qt3Support", SkipAll); +#endif +} + +void tst_QSettings::testCaseSensitivity_data() +{ + populateWithFormats(); +} + +void tst_QSettings::testCaseSensitivity() +{ + QFETCH(QSettings::Format, format); + + for (int pass = 0; pass < 2; ++pass) { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + settings.beginGroup("caseSensitivity"); + + bool cs = true; +#ifndef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER + switch (format) { + case QSettings::NativeFormat: +#ifdef Q_OS_DARWIN + cs = true; +#else + cs = false; +#endif + break; + case QSettings::IniFormat: + cs = false; + break; +#if QT_VERSION >= 0x040100 + case QSettings::CustomFormat1: + cs = true; + break; + case QSettings::CustomFormat2: + cs = false; + break; +#endif + default: + ; + } +#endif + + if (pass == 0) { + settings.setValue("key 1", 1); + settings.setValue("KEY 1", 2); + settings.setValue("key 2", 3); + } + + for (int i = 0; i < 2; ++i) { + QVERIFY(settings.contains("key 1")); + QVERIFY(settings.contains("KEY 1")); + QCOMPARE(settings.value("KEY 1").toInt(), 2); +/* QVERIFY(settings.allKeys().contains("/KEY 1")); + QVERIFY(settings.allKeys().contains("/key 2")); */ + + if (cs) { + QVERIFY(!settings.contains("kEy 1")); + QCOMPARE(settings.value("key 1").toInt(), 1); + QCOMPARE(settings.allKeys().size(), 3); + QVERIFY(settings.allKeys().contains("key 1")); + } else { + QVERIFY(settings.contains("kEy 1")); + QCOMPARE(settings.value("kEy 1").toInt(), 2); + QCOMPARE(settings.value("key 1").toInt(), 2); + QCOMPARE(settings.allKeys().size(), 2); + } + + settings.sync(); + } + + settings.remove("KeY 1"); + + if (cs) { + QVERIFY(!settings.contains("KeY 1")); + QVERIFY(settings.contains("key 1")); + QVERIFY(settings.contains("KEY 1")); + QCOMPARE(settings.value("key 1").toInt(), 1); + QCOMPARE(settings.value("KEY 1").toInt(), 2); + QCOMPARE(settings.allKeys().size(), 3); + } else { + QVERIFY(!settings.contains("KeY 1")); + QVERIFY(!settings.contains("key 1")); + QVERIFY(!settings.contains("KEY 1")); + QCOMPARE(settings.allKeys().size(), 1); + } + settings.setValue("KEY 1", 2); + } +} + +#ifdef QT3_SUPPORT +void tst_QSettings::oldEntryList_data() +{ + oldWriteEntry_data(); +} + +void tst_QSettings::oldReadEntryIni_data() +{ + oldWriteEntry_data(); +} + +void tst_QSettings::oldWriteEntryIni_data() +{ + oldWriteEntry_data(); +} + +void tst_QSettings::oldReadEntry_data() +{ + oldWriteEntry_data(); +} + +void tst_QSettings::oldWriteEntry_data() +{ + // define the test elements we're going to use + QTest::addColumn<QString>("string"); + QTest::addColumn<QString>("empty"); + QTest::addColumn<QString>("unicode"); + QTest::addColumn<int>("integer"); + QTest::addColumn<bool>("boolean"); + QTest::addColumn<double>("floating"); + QTest::addColumn<QStringList>("list"); + + QStringList list0; + list0 << "elem1"; + list0 << "elem2"; + list0 << "elem3"; + list0 << "elem4"; + + QTest::newRow( "data0") << QString("blah") << QString("") << QString( QChar(0x0E12) ) << 99 << TRUE << 3.1415 << list0; + + QStringList list1; + list1 << " elem1"; + list1 << "elem2 "; + list1 << QString(); + list1 << ""; + list1 << "elem3"; + QTest::newRow( "data1") << QString("foo") << QString("") << QString( QChar(0xFEFC) ) << -150 << FALSE << 0.0 << list1; +} + +void tst_QSettings::oldWriteEntryHelper( QSettings &settings ) +{ + QFETCH( QString, string ); + QFETCH( QString, empty ); + QFETCH( QString, unicode ); + QFETCH( int, integer ); + QFETCH( bool, boolean ); + QFETCH( double, floating ); + QFETCH( QStringList, list ); + + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting", string ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/String", string ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/Empty", empty ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/Unicode", unicode ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/Integer", integer ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/Boolean", boolean ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/Floating", floating ) ); + QVERIFY( settings.writeEntry( "/Trolltech/QSettingsTesting/List", list ) ); +} + +void tst_QSettings::oldReadEntryHelper( QSettings &settings ) +{ + bool ok; + + QFETCH( QString, string ); + QFETCH( QString, empty ); + QFETCH( QString, unicode ); + QFETCH( int, integer ); + QFETCH( bool, boolean ); + QFETCH( double, floating ); + QFETCH( QStringList, list ); + + QCOMPARE( settings.readEntry( "/Trolltech/QSettingsTesting", QString::null, &ok ), string ); + QVERIFY( ok ); + QCOMPARE( settings.readEntry( "/Trolltech/QSettingsTesting/String", QString::null, &ok ), string ); + QVERIFY( ok ); + QCOMPARE( settings.readEntry( "/Trolltech/QSettingsTesting/Empty", QString::null, &ok ), empty ); + QVERIFY( ok ); + QCOMPARE( settings.readEntry( "/Trolltech/QSettingsTesting/Unicode", QString::null, &ok ), unicode ); + QVERIFY( ok ); + QCOMPARE( settings.readNumEntry( "/Trolltech/QSettingsTesting/Integer", 0, &ok ), integer ); + QVERIFY( ok ); + QCOMPARE( settings.readBoolEntry( "/Trolltech/QSettingsTesting/Boolean", 0, &ok ), boolean ); + QVERIFY( ok ); + QCOMPARE( settings.readDoubleEntry( "/Trolltech/QSettingsTesting/Floating", 0, &ok ), floating ); + QVERIFY( ok ); + QCOMPARE( settings.readListEntry( "/Trolltech/QSettingsTesting/List", &ok ), list ); + QVERIFY( ok ); + + settings.readListEntry( "/Trolltech/QSettingsTesting/NonExistingValue", &ok ); + QVERIFY( !ok ); +} + +void tst_QSettings::oldWriteEntryIni() +{ + QSettings settings(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + oldWriteEntryHelper(settings); +} + +void tst_QSettings::oldReadEntryIni() +{ + { + QSettings writeSettings(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + oldWriteEntryHelper( writeSettings ); + } + { + QSettings readSettings(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + oldReadEntryHelper( readSettings ); + } +} + + +void tst_QSettings::oldEndGroup_data() +{ + oldBeginGroup_data(); +} + +void tst_QSettings::oldResetGroup_data() +{ + oldBeginGroup_data(); +} + +void tst_QSettings::oldBeginGroup_data() +{ + // define the test elements we're going to use + QTest::addColumn<QString>("group"); + QTest::addColumn<QString>("value"); + + QTest::newRow( "data0") << QString("blah") << "value"; + QTest::newRow( "data1") << QString("") << "first/value"; + QTest::newRow( "data2") << QString("first/second") << "value"; + QTest::newRow( "data3") << QString("first/second/third") << "value"; + QTest::newRow( "data4") << QString("first/second/third") << "value"; +} + +void tst_QSettings::oldBeginGroup() +{ + bool ok; + + QFETCH( QString, group ); + QFETCH( QString, value ); + + QSettings settings("software.org", "KillerAPP"); + + QCOMPARE(settings.group(), QString()); + settings.beginGroup( group ); + QCOMPARE(settings.group(), group); + + QVERIFY( settings.writeEntry( "/" + value, value ) ); + QCOMPARE( settings.readEntry( "/" + value ), value ); + settings.endGroup(); + QCOMPARE( settings.readEntry( group + "/" + value, QString::null, &ok ), value ); + QVERIFY( ok ); +} + +void tst_QSettings::oldEndGroup() +{ + QFETCH( QString, group ); + + QSettings settings("software.org", "KillerAPP"); + QCOMPARE( settings.group(), QString() ); + + settings.beginGroup( group ); + settings.endGroup(); + QCOMPARE( settings.group(), QString() ); + + settings.beginGroup( group ); + settings.beginGroup( group ); + settings.endGroup(); + QCOMPARE( settings.group(), group ); + settings.endGroup(); + QCOMPARE( settings.group(), QString() ); + + QTest::ignoreMessage(QtWarningMsg, "QSettings::endGroup: No matching beginGroup()"); + settings.endGroup(); + QCOMPARE( settings.group(), QString() ); +} + +void tst_QSettings::oldResetGroup() +{ + QFETCH( QString, group ); + + QSettings settings("software.org", "KillerAPP"); + settings.beginGroup( group ); + + settings.resetGroup(); + QCOMPARE( settings.group(), QString() ); +} + +void tst_QSettings::oldEntryList() +{ + { + QSettings writeSettings("software.org", "KillerAPP"); + oldWriteEntryHelper( writeSettings ); + } + + QStringList entryKeys; + entryKeys << "String" << "Empty" << "Unicode" << "Integer" << "Boolean" << "Floating" << "List"; + + QSettings readSettings("software.org", "KillerAPP"); + QStringList entryList = readSettings.entryList( "/Trolltech/QSettingsTesting/" ); + entryKeys.sort(); + entryList.sort(); + QCOMPARE( entryKeys, entryList ); +} + +void tst_QSettings::oldWriteEntry_QString_bool_data() +{ + QTest::addColumn<bool>("b"); + QTest::newRow( "false" ) << bool(FALSE); + QTest::newRow( "true" ) << bool(TRUE); +} + +void tst_QSettings::oldWriteEntry_QString_bool() +{ + { + QSettings writeSettings("software.org", "KillerAPP"); + QFETCH( bool, b ); + QVERIFY( writeSettings.writeEntry( "/Trolltech/QSettingsTesting/Boolean", b ) ); + } + + { + QSettings readSettings("software.org", "KillerAPP"); + QFETCH( bool, b ); + bool ok = FALSE; + QCOMPARE( readSettings.readBoolEntry( "/Trolltech/QSettingsTesting/Boolean", 0, &ok ), b ); + QVERIFY( ok ); + } +} + +void tst_QSettings::oldWriteEntry_QString_double_data() +{ + QTest::addColumn<double>("f"); + QTest::newRow( "data0" ) << 3.1415; + QTest::newRow( "data1" ) << 0.0; + QTest::newRow( "data2" ) << 0.0000000000000000000000000001; +} + +void tst_QSettings::oldWriteEntry_QString_double() +{ + { + QSettings writeSettings("software.org", "KillerAPP"); + QFETCH( double, f ); + QVERIFY( writeSettings.writeEntry( "/Trolltech/QSettingsTesting/Floating", f ) ); + } + { + QSettings readSettings("software.org", "KillerAPP"); + QFETCH( double, f ); + bool ok = FALSE; + QCOMPARE( readSettings.readDoubleEntry( "/Trolltech/QSettingsTesting/Floating", 0, &ok ), f ); + QVERIFY( ok ); + } +} + +void tst_QSettings::oldWriteEntry_QString_int_data() +{ + QTest::addColumn<int>("i"); + QTest::newRow( "data0" ) << int(0); + QTest::newRow( "data1" ) << int(1); + QTest::newRow( "data2" ) << int(11); + QTest::newRow( "data3" ) << int(111); + QTest::newRow( "data4" ) << int(1111); + QTest::newRow( "data5" ) << int(11111); + QTest::newRow( "data6" ) << int(-1); + QTest::newRow( "data7" ) << int(-11); + QTest::newRow( "data8" ) << int(-111); + QTest::newRow( "data9" ) << int(-1111); + QTest::newRow( "data10" ) << int(-11111); +} + +void tst_QSettings::oldWriteEntry_QString_int() +{ + { + QSettings writeSettings("software.org", "KillerAPP"); + QFETCH( int, i ); + QVERIFY( writeSettings.writeEntry( "/Trolltech/QSettingsTesting/Integer", i ) ); + } + { + QSettings readSettings("software.org", "KillerAPP"); + QFETCH( int, i ); + bool ok = FALSE; + QCOMPARE( readSettings.readNumEntry( "/Trolltech/QSettingsTesting/Integer", 0, &ok ), i ); + QVERIFY( ok ); + } +} + +void tst_QSettings::oldWriteEntry_QString_QString_data() +{ + QTest::addColumn<QString>("s"); + QTest::newRow( "data0" ) << QString( "blah" ); + QTest::newRow( "data1" ) << QString( "" ); + QTest::newRow( "data2" ) << QString( QChar(0x0E12) ); // unicode + QTest::newRow( "data3" ) << QString("foo"); +// QTest::newRow( "data4" ) << QString::null; // nul string (not supported on Windows!) + QTest::newRow( "data5" ) << QString( QChar(0xFEFC) ); // more unicode + QTest::newRow( "data6" ) << QString( "This is s short string" ); + QTest::newRow( "data7" ) << QString( "This is a string with a cr\nand some text on the second line" ); + QTest::newRow( "data8" ) << QString( "\n" ); + QTest::newRow( "data9" ) << QString( "01234567890, abcdefghijklmnopqrestuvxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_+=-[{]}\\|'\":;/?.>,<" ); +} + +void tst_QSettings::oldWriteEntry_QString_QString() +{ + { + QSettings writeSettings("software.org", "KillerAPP"); + QFETCH( QString, s ); + QVERIFY( writeSettings.writeEntry( "/Trolltech/QSettingsTesting/String", s ) ); + } + { + QSettings readSettings("software.org", "KillerAPP"); + QFETCH( QString, s ); + bool ok = FALSE; +#ifdef Q_OS_WIN + if (qWinVersion() & Qt::WV_DOS_based) { + QEXPECT_FAIL("data2", "Windows 9x does not support unicode characters in the registry", Abort); + QEXPECT_FAIL("data5", "Windows 9x does not support unicode characters in the registry", Abort); + } +#endif + QCOMPARE( readSettings.readEntry( "/Trolltech/QSettingsTesting/String", QString::null, &ok ), s ); + QVERIFY( ok ); + } +} + +void tst_QSettings::oldWriteEntry_QString_QStringList_data() +{ + QTest::addColumn<QStringList>("l"); + QStringList list0; + list0 << "elem1"; + list0 << "elem2"; + list0 << "elem3"; + list0 << "elem4"; + + QTest::newRow( "data0") << list0; + + QStringList list1; + list1 << " elem1"; + list1 << "elem2 "; + list1 << QString(); + list1 << ""; + list1 << "elem3"; + QTest::newRow( "data1") << list1; + + QStringList list2; + list2 << " elem1"; + list2 << "elem2 bla bla bla, yada yada, 01234567890, abcdefghijklmnopqrestuvxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_+=-[{]}\\|'\":;/?.>,<"; + list1 << QString(); + list2 << "\n"; + list2 << "elem3\nand another line"; + QTest::newRow( "data2") << list2; +} + +void tst_QSettings::oldWriteEntry_QString_QStringList() +{ + { + QSettings writeSettings("software.org", "KillerAPP"); + QFETCH( QStringList, l ); + QVERIFY( writeSettings.writeEntry( "/Trolltech/QSettingsTesting/List", l ) ); + } + { + QSettings readSettings("software.org", "KillerAPP"); + QFETCH( QStringList, l ); + bool ok = FALSE; + QCOMPARE( readSettings.readListEntry( "/Trolltech/QSettingsTesting/List", &ok ), l ); + QVERIFY( ok ); + } +} + +void tst_QSettings::oldWriteEntry_QString_QStringList_QChar_data() +{ + QTest::addColumn<QStringList>("l"); + QTest::addColumn<QString>("sep"); + + QStringList list0; + list0 << "elem1"; + list0 << "elem2"; + list0 << "elem3"; + list0 << "elem4"; + + QTest::newRow( "data00") << list0 << "\\"; + QTest::newRow( "data01") << list0 << "/"; + QTest::newRow( "data02") << list0 << " "; + + QStringList list1; + list1 << " elem1"; + list1 << "elem2 "; + list1 << "elem3"; + QTest::newRow( "data10") << list1 << "\\"; + QTest::newRow( "data11") << list1 << "/"; + QTest::newRow( "data12") << list1 << "&"; + + QStringList list2; + list2 << " elem1"; + list2 << "elem2 bla bla bla, yada yada, 01234567890, abcdefghijklmnopqrestuvxyz, ABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^*()_+=-[{]}\\|/'\":;?.>,<"; + list2 << "\n"; + list2 << "elem3\nand another line"; + QTest::newRow( "data20") << list2 << "&"; + + // an empty stringlist should be stored as an empty string (and return an empty stringlist?) + QStringList list3; + QTest::newRow( "data30") << list3 << "/"; +} + +void tst_QSettings::oldWriteEntry_QString_QStringList_QChar() +{ + // edba: + // data10, data11, data12, data20, data21 and data22 currently fail. + // This is because the list DOES contain the separator which is a fail IMO, so i + // expect the writeEntry to return FALSE (but it doesn't). + // If my interpretation of the doc is wrong, then the separators should be deleted from + // data10 .. data22. + { + QSettings writeSettings("software.org", "KillerAPP"); + QFETCH( QStringList, l ); + QFETCH( QString, sep ); + QVERIFY( writeSettings.writeEntry( "/Trolltech/QSettingsTesting/List", l, QChar(sep[0]) ) ); + } + { + QSettings readSettings("software.org", "KillerAPP"); + QFETCH( QStringList, l ); + QFETCH( QString, sep ); + bool ok = FALSE; + QStringList actual; + actual = readSettings.readListEntry( "/Trolltech/QSettingsTesting/List", QChar(sep[0]), &ok ); + QVERIFY2( ok, "Read the stringlist from the settings" ); + QCOMPARE( actual, l ); + } +} + +void tst_QSettings::oldReadListEntry_QString() +{ + DEPENDS_ON( "writeEntry_QString_QStringList" ); +} + +void tst_QSettings::oldReadListEntry_QString_QChar() +{ + DEPENDS_ON( "writeEntry_QString_QStringList_QChar" ); +} + +void tst_QSettings::oldReadEntry() +{ + DEPENDS_ON( "writeEntry_QString_QString" ); +} + +void tst_QSettings::oldReadNumEntry() +{ + DEPENDS_ON( "writeEntry_QString_int" ); +} + +void tst_QSettings::oldReadDoubleEntry() +{ + DEPENDS_ON( "writeEntry_QString_double" ); +} + +void tst_QSettings::oldReadBoolEntry() +{ + DEPENDS_ON( "writeEntry_QString_bool" ); +} + +void tst_QSettings::oldRemoveEntry() +{ + // we'll use this one later + QSettings firstSettings("software.org", "KillerAPP"); + + // first write a key + { + QSettings writeSettings("software.org", "KillerAPP"); + writeSettings.writeEntry( "/Trolltech/QSettingsTesting/removeEntry", "foobar" ); + } + + // check that the key exists + { + QSettings readSettings("software.org", "KillerAPP"); + bool ok = FALSE; + QString foo = readSettings.readEntry( "/Trolltech/QSettingsTesting/removeEntry", QString::null, &ok ); + QVERIFY( ok ); + QVERIFY( foo == "foobar" ); + + // and remove it + QVERIFY( readSettings.removeEntry( "/Trolltech/QSettingsTesting/removeEntry") ); + + // check that it is gone + QString foo2 = readSettings.readEntry( "/Trolltech/QSettingsTesting/removeEntry", QString::null, &ok ); + QVERIFY( ok == FALSE ); + QVERIFY( foo2 == "" ); + } + + // Take another chance with a fresh instance + { + QSettings readSettings("software.org", "KillerAPP"); + bool ok = FALSE; + QString foo = readSettings.readEntry( "/Trolltech/QSettingsTesting/removeEntry", QString::null, &ok ); + QVERIFY( ok == FALSE ); + QVERIFY( foo == "" ); + } + + // and another chance with an instance that existed already + { + bool ok = FALSE; + QString foo = firstSettings.readEntry( "/Trolltech/QSettingsTesting/removeEntry", QString::null, &ok ); + QVERIFY( ok == FALSE ); + QVERIFY( foo == "" ); + } +} + +void tst_QSettings::oldGlobalVersusLocal() +{ + { //write global + QSettings settings("foo"); + settings.setPath("software.org", "KillerAPP", QSettings::Global); + settings.writeEntry("/vs/just_global/", "from Global"); + settings.writeEntry("/vs/local_and_global/", "from Global"); + } + { //write local + QSettings settings("bar"); + settings.setPath("software.org", "KillerAPP", QSettings::User); + settings.writeEntry("/vs/local_and_global/", "from User"); + } + bool ok; + { + QSettings settings("baz"); + settings.setPath("software.org", "KillerAPP", QSettings::User); + QString just_global = settings.readEntry("/vs/just_global/", "not_available", &ok); + QVERIFY(ok); + QCOMPARE(just_global, QString("from Global")); + QString local_and_global = settings.readEntry("/vs/local_and_global/", "not_available", &ok); + QVERIFY(ok); + QCOMPARE(local_and_global, QString("from User")); + } + { + QSettings settings("bat"); + settings.setPath("software.org", "KillerAPP", QSettings::Global); + QString just_global = settings.readEntry("/vs/just_global/", "not_available", &ok); + QVERIFY(ok); + QCOMPARE(just_global, QString("from Global")); + QString local_and_global = settings.readEntry("/vs/local_and_global/", "not_available", &ok); + QVERIFY(ok); + QCOMPARE(local_and_global, QString("from Global")); + } +} +#endif // QT3_SUPPORT + +void tst_QSettings::fileName() +{ +#ifdef Q_OS_MAC + QSettings s1(QSettings::UserScope, "Apple", "Console"); + QSettings s2(QSettings::UserScope, "Apple"); + QSettings s3(QSettings::SystemScope, "Apple", "Console"); + QSettings s4(QSettings::SystemScope, "Apple"); + + QCOMPARE(s1.fileName(), QDir::homePath() + "/Library/Preferences/com.apple.Console.plist"); + QCOMPARE(s2.fileName(), QDir::homePath() + "/Library/Preferences/com.apple.plist"); + QCOMPARE(s3.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + QCOMPARE(s4.fileName(), QString("/Library/Preferences/com.apple.plist")); + + QSettings s5(QSettings::SystemScope, "Apple.com", "Console"); + QCOMPARE(s5.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s6(QSettings::SystemScope, "apple.com", "Console"); + QCOMPARE(s6.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s7(QSettings::SystemScope, "apple.Com", "Console"); + QCOMPARE(s7.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s8(QSettings::SystemScope, "apple.fr", "Console"); + QCOMPARE(s8.fileName(), QString("/Library/Preferences/fr.apple.Console.plist")); + + QSettings s9(QSettings::SystemScope, "apple.co.jp", "Console"); + QCOMPARE(s9.fileName(), QString("/Library/Preferences/jp.co.apple.Console.plist")); + + QSettings s10(QSettings::SystemScope, "apple.org", "Console"); + QCOMPARE(s10.fileName(), QString("/Library/Preferences/org.apple.Console.plist")); + + QSettings s11(QSettings::SystemScope, "apple.net", "Console"); + QCOMPARE(s11.fileName(), QString("/Library/Preferences/net.apple.Console.plist")); + + QSettings s12(QSettings::SystemScope, "apple.museum", "Console"); + QCOMPARE(s12.fileName(), QString("/Library/Preferences/museum.apple.Console.plist")); + + QSettings s13(QSettings::SystemScope, "apple.FR", "Console"); + QCOMPARE(s13.fileName(), QString("/Library/Preferences/fr.apple.Console.plist")); + + QSettings s14(QSettings::SystemScope, "apple.mUseum", "Console"); + QCOMPARE(s14.fileName(), QString("/Library/Preferences/museum.apple.Console.plist")); + + QSettings s15(QSettings::SystemScope, "apple.zz", "Console"); + QCOMPARE(s15.fileName(), QString("/Library/Preferences/zz.apple.Console.plist")); + + QSettings s15_prime(QSettings::SystemScope, "apple.foo", "Console"); + QCOMPARE(s15_prime.fileName(), QString("/Library/Preferences/com.apple-foo.Console.plist")); + + QSettings s16(QSettings::SystemScope, "apple.f", "Console"); + QCOMPARE(s16.fileName(), QString("/Library/Preferences/com.apple-f.Console.plist")); + + QSettings s17(QSettings::SystemScope, "apple.", "Console"); + QCOMPARE(s17.fileName(), QString("/Library/Preferences/com.apple.Console.plist")); + + QSettings s18(QSettings::SystemScope, "Foo, Inc.", "Console"); + QCOMPARE(s18.fileName(), QString("/Library/Preferences/com.foo-inc.Console.plist")); + + QSettings s19(QSettings::SystemScope, "Foo, Inc.com", "Console"); + QCOMPARE(s19.fileName(), QString("/Library/Preferences/com.foo, inc.Console.plist")); + + QSettings s20(QSettings::SystemScope, QLatin1String(" ") + QChar(0xbd) + QLatin1String("Foo//:/Barxxx Baz!()#@.com"), "Console"); + QCOMPARE(s20.fileName(), QLatin1String("/Library/Preferences/com. ") + QChar(0xbd) + QLatin1String("foo : barxxx baz!()#@.Console.plist")); + + QSettings s21(QSettings::SystemScope, QLatin1String(" ") + QChar(0xbd) + QLatin1String("Foo//:/Bar,,, Baz!()#"), "Console"); + QCOMPARE(s21.fileName(), QString("/Library/Preferences/com.foo-bar-baz.Console.plist")); +#else + QSKIP("Please write a fileName() test for the other platforms", SkipAll); +#endif +} + +void tst_QSettings::isWritable_data() +{ + populateWithFormats(); +} + +void tst_QSettings::isWritable() +{ + QFETCH(QSettings::Format, format); + + { + QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP"); + s1.setValue("foo", 1); + s1.sync(); + // that should create the file + } + + { + QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QVERIFY(s1.isWritable()); + } + + { + QSettings s1(format, QSettings::SystemScope, "software.org", "KillerAPP"); + s1.setValue("foo", 1); + s1.sync(); + // that should create the file, *if* we have the permissions + } + + { + QSettings s1(format, QSettings::SystemScope, "software.org", "KillerAPP"); + QSettings s2(format, QSettings::SystemScope, "software.org", "Something Different"); + QSettings s3(format, QSettings::SystemScope, "foo.org", "Something Different"); + if (s1.contains("foo")) { + QVERIFY(s1.isWritable()); + QVERIFY(s2.isWritable()); + QVERIFY(s3.isWritable()); + } else { + QVERIFY(!s1.isWritable()); + QVERIFY(!s2.isWritable()); + QVERIFY(!s3.isWritable()); + } + } +} + +void tst_QSettings::childGroups_data() +{ + populateWithFormats(); +} + +void tst_QSettings::childGroups() +{ + QFETCH(QSettings::Format, format); + + { + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setValue("alpha", "1"); + settings.setValue("alpha/a", "2"); + settings.setValue("alpha/b", "3"); + settings.setValue("alpha/c", "4"); + settings.setValue("beta", "5"); + settings.setValue("gamma", "6"); + settings.setValue("gamma/d", "7"); + settings.setValue("gamma/d/e", "8"); + settings.setValue("gamma/f/g", "9"); + settings.setValue("omicron/h/i/j/x", "10"); + settings.setValue("omicron/h/i/k/y", "11"); + settings.setValue("zeta/z", "12"); + } + + for (int pass = 0; pass < 3; ++pass) { + QConfFile::clearCache(); + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setFallbacksEnabled(false); + if (pass == 1) { + settings.value("gamma/d"); + } else if (pass == 2) { + settings.value("gamma"); + } + + settings.beginGroup("gamma"); + QCOMPARE(settings.childGroups(), QStringList() << "d" << "f"); + settings.beginGroup("d"); + QCOMPARE(settings.childGroups(), QStringList()); + settings.endGroup(); + settings.endGroup(); + + settings.beginGroup("alpha"); + QCOMPARE(settings.childGroups(), QStringList()); + settings.endGroup(); + + settings.beginGroup("d"); + QCOMPARE(settings.childGroups(), QStringList()); + settings.endGroup(); + + settings.beginGroup("/omicron///h/i///"); + QCOMPARE(settings.childGroups(), QStringList() << "j" << "k"); + settings.endGroup(); + + settings.beginGroup("////"); + QCOMPARE(settings.childGroups(), QStringList() << "alpha" << "gamma" << "omicron" << "zeta"); + settings.endGroup(); + + QCOMPARE(settings.childGroups(), QStringList() << "alpha" << "gamma" << "omicron" << "zeta"); + } +} + +void tst_QSettings::childKeys_data() +{ + populateWithFormats(); +} + +void tst_QSettings::childKeys() +{ + QFETCH(QSettings::Format, format); + + { + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setValue("alpha", "1"); + settings.setValue("alpha/a", "2"); + settings.setValue("alpha/b", "3"); + settings.setValue("alpha/c", "4"); + settings.setValue("beta", "5"); + settings.setValue("gamma", "6"); + settings.setValue("gamma/d", "7"); + settings.setValue("gamma/d/e", "8"); + settings.setValue("gamma/f/g", "9"); + settings.setValue("omicron/h/i/j/x", "10"); + settings.setValue("omicron/h/i/k/y", "11"); + settings.setValue("zeta/z", "12"); + } + + for (int pass = 0; pass < 3; ++pass) { + QConfFile::clearCache(); + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setFallbacksEnabled(false); + if (pass == 1) { + settings.value("gamma/d"); + } else if (pass == 2) { + settings.value("gamma"); + } + + settings.beginGroup("gamma"); + QCOMPARE(settings.childKeys(), QStringList() << "d"); + settings.beginGroup("d"); + QCOMPARE(settings.childKeys(), QStringList() << "e"); + settings.endGroup(); + settings.endGroup(); + + settings.beginGroup("alpha"); + QCOMPARE(settings.childKeys(), QStringList() << "a" << "b" << "c"); + settings.endGroup(); + + settings.beginGroup("d"); + QCOMPARE(settings.childKeys(), QStringList()); + settings.endGroup(); + + settings.beginGroup("/omicron///h/i///"); + QCOMPARE(settings.childKeys(), QStringList()); + settings.endGroup(); + + settings.beginGroup("////"); + QCOMPARE(settings.childKeys(), QStringList() << "alpha" << "beta" << "gamma"); + settings.endGroup(); + + QCOMPARE(settings.childKeys(), QStringList() << "alpha" << "beta" << "gamma"); + } +} + +void tst_QSettings::allKeys_data() +{ + populateWithFormats(); +} + +void tst_QSettings::allKeys() +{ + QFETCH(QSettings::Format, format); + + QStringList allKeys; + allKeys << "alpha" << "alpha/a" << "alpha/b" << "alpha/c" << "beta" << "gamma" << "gamma/d" + << "gamma/d/e" << "gamma/f/g" << "omicron/h/i/j/x" << "omicron/h/i/k/y" << "zeta/z"; + + { + QSettings settings(format, QSettings::SystemScope, "software.org"); + for (int i = 0; i < allKeys.size(); ++i) + settings.setValue(allKeys.at(i), QString::number(i + 1)); + } + + for (int pass = 0; pass < 3; ++pass) { + QConfFile::clearCache(); + QSettings settings(format, QSettings::SystemScope, "software.org"); + settings.setFallbacksEnabled(false); + + if (pass == 1) { + settings.value("gamma/d"); + } else if (pass == 2) { + settings.value("gamma"); + } + + settings.beginGroup("gamma"); + QCOMPARE(settings.allKeys(), QStringList() << "d" << "d/e" << "f/g"); + settings.beginGroup("d"); + QCOMPARE(settings.allKeys(), QStringList() << "e"); + settings.endGroup(); + settings.endGroup(); + + settings.beginGroup("alpha"); + QCOMPARE(settings.allKeys(), QStringList() << "a" << "b" << "c"); + settings.endGroup(); + + settings.beginGroup("d"); + QCOMPARE(settings.allKeys(), QStringList()); + settings.endGroup(); + + settings.beginGroup("/omicron///h/i///"); + QCOMPARE(settings.allKeys(), QStringList() << "j/x" << "k/y"); + settings.endGroup(); + + settings.beginGroup("////"); + QCOMPARE(settings.allKeys(), allKeys); + settings.endGroup(); + + QCOMPARE(settings.allKeys(), allKeys); + } +} + +#if QT_VERSION >= 0x040100 +void tst_QSettings::registerFormat() +{ + QSettings settings1(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settings2(QSettings::CustomFormat1, QSettings::UserScope, "software.org", "KillerAPP"); + + QString fileName = settings1.fileName(); + fileName.chop(3); // "ini"; + fileName.append("custom1"); + QCOMPARE(settings2.fileName(), fileName); + + // OK, let's see if it can read a generated file of a custom type + // Beware: readCustom3File() and writeCustom3File() have unintuitive behavior + // so we can test error handling + + QSettings::Format custom3 = QSettings::registerFormat("custom3", readCustom3File, writeCustom3File); + QVERIFY(custom3 == QSettings::CustomFormat3); + + QDir dir(settingsPath()); + QVERIFY(dir.mkpath("someDir")); + QFile f(dir.path()+"/someDir/someSettings.custom3"); + + QVERIFY(f.open(QFile::WriteOnly)); + f.write("OK"); + f.close(); + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3); + QCOMPARE(settings.status(), QSettings::NoError); + QCOMPARE(settings.value("retval").toString(), QString("OK")); + QVERIFY(settings.isWritable()); + } + + QVERIFY(f.open(QFile::WriteOnly)); + f.write("NotOK"); + f.close(); + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3); + QCOMPARE(settings.status(), QSettings::FormatError); + QCOMPARE(settings.value("retval").toString(), QString()); + QVERIFY(settings.isWritable()); + } + + QVERIFY(f.open(QFile::WriteOnly)); + f.write("OK"); + f.close(); + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3); + QCOMPARE(settings.status(), QSettings::NoError); + settings.setValue("zzz", "bar"); + settings.sync(); + QCOMPARE(settings.status(), QSettings::NoError); + + settings.setValue("retval", "NotOK"); + settings.sync(); + QCOMPARE(settings.status(), QSettings::AccessError); + + QCOMPARE(settings.value("retval").toString(), QString("NotOK")); + QVERIFY(settings.isWritable()); + } + + { + QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat4); + QCOMPARE(settings.status(), QSettings::AccessError); + QVERIFY(!settings.isWritable()); + } +} + +void tst_QSettings::setPath() +{ +#define TEST_PATH(doSet, ext, format, scope, path) \ + { \ + if (doSet) \ + QSettings::setPath(QSettings::format, QSettings::scope, settingsPath(path)); \ + QSettings settings1(QSettings::format, QSettings::scope, "software.org", "KillerAPP"); \ + QCOMPARE(QDir(settings1.fileName()), QDir(settingsPath(path) + QDir::separator() + "software.org" \ + + QDir::separator() + "KillerAPP." + ext)); \ + } + + /* + The first pass checks that setPath() works; the second + path checks that it has no bad side effects. + */ + for (int i = 0; i < 2; ++i) { +#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) + TEST_PATH(i == 0, "conf", NativeFormat, UserScope, "alpha") + TEST_PATH(i == 0, "conf", NativeFormat, SystemScope, "beta") +#endif + TEST_PATH(i == 0, "ini", IniFormat, UserScope, "gamma") + TEST_PATH(i == 0, "ini", IniFormat, SystemScope, "omicron") + TEST_PATH(i == 0, "custom1", CustomFormat1, UserScope, "epsilon") + TEST_PATH(i == 0, "custom1", CustomFormat1, SystemScope, "zeta") + TEST_PATH(i == 0, "custom2", CustomFormat2, UserScope, "eta") + TEST_PATH(i == 0, "custom2", CustomFormat2, SystemScope, "iota") + } +} +#endif + +void tst_QSettings::setDefaultFormat() +{ + QVERIFY(QSettings::defaultFormat() == QSettings::NativeFormat); + + QSettings::setDefaultFormat(QSettings::CustomFormat1); + QSettings settings1("org", "app"); + QSettings settings2(QSettings::SystemScope, "org", "app"); + QSettings settings3; + + QVERIFY(settings1.format() == QSettings::NativeFormat); + QVERIFY(settings2.format() == QSettings::NativeFormat); + QVERIFY(settings3.format() == QSettings::CustomFormat1); + + QSettings::setDefaultFormat(QSettings::NativeFormat); + QVERIFY(QSettings::defaultFormat() == QSettings::NativeFormat); + + QVERIFY(settings1.format() == QSettings::NativeFormat); + QVERIFY(settings2.format() == QSettings::NativeFormat); + QVERIFY(settings3.format() == QSettings::CustomFormat1); +} + +void tst_QSettings::dontCreateNeedlessPaths() +{ + QString path; + { + QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Hello", "Test"); + QVariant val = settings.value("foo", "bar"); + path = settings.fileName(); + } + + QFileInfo fileInfo(path); + QVERIFY(!fileInfo.dir().exists()); +} + +#ifndef Q_OS_WIN +void tst_QSettings::dontReorderIniKeysNeedlessly() +{ +#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER + QSKIP("This Qt build does not preserve ordering, as a code size optimization.", SkipAll); +#endif + + /* + This is a very strong test. It asserts that modifying + resourcefile2.ini will lead to the exact contents of + resourcefile3.ini. Right now it's run only on Unix + systems, but that should be enough since the INI + code (unlike this test) is platform-agnostic. + + Things that are tested: + + * keys are written in the same order that they were + read in + + * new keys are put at the end of their respective + sections + */ + + QFile inFile(":/resourcefile2.ini"); + inFile.open(QIODevice::ReadOnly); + QByteArray contentsBefore = inFile.readAll(); + inFile.close(); + + QByteArray expectedContentsAfter; + + { + QFile inFile(":/resourcefile3.ini"); + inFile.open(QIODevice::ReadOnly); + expectedContentsAfter = inFile.readAll(); + inFile.close(); + } + + QString outFileName; + QString outFileName2; + + QTemporaryFile outFile; + outFile.open(); + outFile.write(contentsBefore); + outFileName = outFile.fileName(); + outFile.close(); + + QSettings settings(outFileName, QSettings::IniFormat); + QVERIFY(settings.status() == QSettings::NoError); + QVERIFY(settings.isWritable()); + + settings.setValue("Field 1/Bottom", 90); + settings.setValue("Field 1/x", 1); + settings.setValue("Field 1/y", 1); + settings.setValue("Field 1/width", 1); + settings.setValue("Field 1/height", 1); + settings.sync(); + + QFile outFile2(outFileName); + QVERIFY(outFile2.open(QIODevice::ReadOnly)); + QCOMPARE(outFile2.readAll(), expectedContentsAfter); + outFile2.close(); +} +#endif + +void tst_QSettings::rainersSyncBugOnMac_data() +{ + ctor_data(); +} + +void tst_QSettings::rainersSyncBugOnMac() +{ + QFETCH(QSettings::Format, format); + + QString fileName; + + { + QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP"); + QCOMPARE(s1.value("key1", 5).toInt(), 5); + fileName = s1.fileName(); + } + + { + QSettings s2(fileName, format); + s2.setValue("key1", 25); + } + + { + QSettings s3(format, QSettings::UserScope, "software.org", "KillerAPP"); + QCOMPARE(s3.value("key1", 30).toInt(), 25); + } +} + +void tst_QSettings::recursionBug() +{ + QPixmap pix(10,10); + pix.fill("blue"); + + { + QSettings settings(settingsPath("starrunner.ini"), QSettings::IniFormat); + settings.setValue("General/Pixmap", pix ); + } +} + +#ifdef QT3_SUPPORT +void tst_QSettings::setPathBug() +{ + QSettings settings("software.org", "KillerAPP", this); + settings.setPath("foo.org", "Bar", QSettings::User); + QVERIFY(settings.parent() == this); + settings.setValue("blah", "BAZ"); + settings.setPath("bar.org", "Baz", QSettings::User); + settings.setValue("blah", "BAZ"); + QVERIFY(settings.parent() == this); +} +#endif + +/* +// Not tested at the moment. +void tst_QSettings::oldSubkeyList() +{ + QVERIFY( TRUE ); +} +*/ + +QTEST_MAIN(tst_QSettings) +#include "tst_qsettings.moc" + + +// foo |