diff options
Diffstat (limited to 'tests/auto/corelib/io/qsettings')
-rw-r--r-- | tests/auto/corelib/io/qsettings/.gitattributes | 2 | ||||
-rw-r--r-- | tests/auto/corelib/io/qsettings/CMakeLists.txt | 44 | ||||
-rw-r--r-- | tests/auto/corelib/io/qsettings/qt5settings.ini | 11 | ||||
-rw-r--r-- | tests/auto/corelib/io/qsettings/resourcefile4.ini | 2 | ||||
-rw-r--r-- | tests/auto/corelib/io/qsettings/resourcefile5.ini | 2 | ||||
-rw-r--r-- | tests/auto/corelib/io/qsettings/tst_qsettings.cpp | 544 | ||||
-rw-r--r-- | tests/auto/corelib/io/qsettings/utf8settings.ini | 11 |
7 files changed, 349 insertions, 267 deletions
diff --git a/tests/auto/corelib/io/qsettings/.gitattributes b/tests/auto/corelib/io/qsettings/.gitattributes index a4ad8d7644..920df33b54 100644 --- a/tests/auto/corelib/io/qsettings/.gitattributes +++ b/tests/auto/corelib/io/qsettings/.gitattributes @@ -1,5 +1,3 @@ resourcefile.ini -crlf resourcefile2.ini -crlf resourcefile3.ini -crlf -resourcefile4.ini -crlf -resourcefile5.ini -crlf diff --git a/tests/auto/corelib/io/qsettings/CMakeLists.txt b/tests/auto/corelib/io/qsettings/CMakeLists.txt index 55a360166b..e68b2644af 100644 --- a/tests/auto/corelib/io/qsettings/CMakeLists.txt +++ b/tests/auto/corelib/io/qsettings/CMakeLists.txt @@ -1,39 +1,39 @@ -# Generated from qsettings.pro. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause ##################################################################### ## tst_qsettings Test: ##################################################################### -qt_internal_add_test(tst_qsettings - SOURCES - tst_qsettings.cpp - DEFINES - QT_DISABLE_DEPRECATED_BEFORE=0 - INCLUDE_DIRECTORIES - ../../kernel/qmetatype - PUBLIC_LIBRARIES - Qt::CorePrivate - Qt::Gui -) +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qsettings LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() -# Resources: +# Test: set(qsettings_resource_files "bom.ini" "resourcefile.ini" "resourcefile2.ini" "resourcefile3.ini" - "resourcefile4.ini" - "resourcefile5.ini" "resourcefile6.plist" "withcomments.ini" "float.ini" + "qt5settings.ini" + "utf8settings.ini" ) -qt_internal_add_resource(tst_qsettings "qsettings" - PREFIX - "/" - FILES - ${qsettings_resource_files} +qt_internal_add_test(tst_qsettings + SOURCES + tst_qsettings.cpp + INCLUDE_DIRECTORIES + ../../kernel/qmetatype + LIBRARIES + Qt::CorePrivate + Qt::Gui + TESTDATA ${qsettings_resource_files} + BUILTIN_TESTDATA ) @@ -41,11 +41,11 @@ qt_internal_add_resource(tst_qsettings "qsettings" ##################################################################### qt_internal_extend_target(tst_qsettings CONDITION MSVC - PUBLIC_LIBRARIES + LIBRARIES advapi32 ) qt_internal_extend_target(tst_qsettings CONDITION APPLE - PUBLIC_LIBRARIES + LIBRARIES ${FWCoreFoundation} ) diff --git a/tests/auto/corelib/io/qsettings/qt5settings.ini b/tests/auto/corelib/io/qsettings/qt5settings.ini new file mode 100644 index 0000000000..59239d29f3 --- /dev/null +++ b/tests/auto/corelib/io/qsettings/qt5settings.ini @@ -0,0 +1,11 @@ +[General] +.%2C%27%25U%U0430%U0431%U0432%U0433%22%09=".,'%!@#$" +%U265F=\x2658\x265a +%UD83C%UDF0D=\xd83c\xdf10 + +[Test] +BAR=BAR +B%C4R=B\xc4R +OST=OST +%D6SE=\xd6SE +%U042D%U0442%U043E\%U0442%U0435%U0441%U0442=\x42d\x442\x43e \x442\x435\x441\x442 diff --git a/tests/auto/corelib/io/qsettings/resourcefile4.ini b/tests/auto/corelib/io/qsettings/resourcefile4.ini deleted file mode 100644 index 09c21b1591..0000000000 --- a/tests/auto/corelib/io/qsettings/resourcefile4.ini +++ /dev/null @@ -1,2 +0,0 @@ -[Fa%E7ade] -QU%C9BEC=Façade/QUÉBEC diff --git a/tests/auto/corelib/io/qsettings/resourcefile5.ini b/tests/auto/corelib/io/qsettings/resourcefile5.ini deleted file mode 100644 index d2d2103560..0000000000 --- a/tests/auto/corelib/io/qsettings/resourcefile5.ini +++ /dev/null @@ -1,2 +0,0 @@ -[Fa%E7ade] -QU%C9BEC=Faade/QUBEC diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp index 48087b6a65..f4d7f076ef 100644 --- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp +++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp @@ -1,52 +1,23 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QTest> #include <QtCore/QSettings> #include <private/qsettings_p.h> + +#include "tst_qmetatype_common.h" + #include <QtCore/QCoreApplication> -#include <QtCore/QDateTime> -#include <QtCore/QtGlobal> -#include <QtCore/QMetaType> -#include <QtCore/QString> #include <QtCore/QDir> +#include <QtCore/QEventLoop> +#include <QtCore/QtGlobal> #include <QtCore/QThread> #include <QtCore/QSysInfo> #if QT_CONFIG(shortcut) # include <QtGui/QKeySequence> #endif -#include <QtCore> -#include <QtGui> -#include "tst_qmetatype_common.h" - #include <cctype> #include <stdlib.h> #if defined(Q_OS_WIN) && defined(Q_CC_GNU) @@ -71,6 +42,13 @@ #include "qplatformdefs.h" #endif +#if defined(Q_OS_WASM) +#include <QtCore/private/qstdweb_p.h> + +#include "emscripten/threading.h" +#include "emscripten/val.h" +#endif + Q_DECLARE_METATYPE(QSettings::Format) #ifndef QSETTINGS_P_H_VERSION @@ -108,6 +86,20 @@ static inline bool canWriteNativeSystemSettings() static const char insufficientPermissionSkipMessage[] = "Insufficient permissions for this test."; +static void populateWithFormats() +{ + QTest::addColumn<QSettings::Format>("format"); + + QTest::newRow("native") << QSettings::NativeFormat; +#if defined(Q_OS_WASM) + if (qstdweb::haveJspi()) + QTest::newRow("idb") << QSettings::WebIndexedDBFormat; +#endif // defined(Q_OS_WASM) + QTest::newRow("ini") << QSettings::IniFormat; + QTest::newRow("custom1") << QSettings::CustomFormat1; + QTest::newRow("custom2") << QSettings::CustomFormat2; +} + class tst_QSettings : public QObject { Q_OBJECT @@ -120,8 +112,11 @@ public slots: void cleanup() { cleanupTestFiles(); } private slots: void getSetCheck(); - void ctor_data(); + void ctor_data() { populateWithFormats(); } void ctor(); +#ifdef Q_OS_WASM + void idb(); +#endif void beginGroup(); void setValue(); void remove(); @@ -132,16 +127,16 @@ private slots: void syncAlternateDataStream(); #endif void setFallbacksEnabled(); - void setFallbacksEnabled_data(); - void fromFile_data(); + void setFallbacksEnabled_data() { populateWithFormats(); } + void fromFile_data() { populateWithFormats(); } void fromFile(); - void testArrays_data(); + void testArrays_data() { populateWithFormats(); } void testArrays(); - void testCaseSensitivity_data(); + void testCaseSensitivity_data() { populateWithFormats(); } void testCaseSensitivity(); void testErrorHandling_data(); void testErrorHandling(); - void testChildKeysAndGroups_data(); + void testChildKeysAndGroups_data() { populateWithFormats(); } void testChildKeysAndGroups(); void testUpdateRequestEvent(); void testThreadSafety(); @@ -151,10 +146,10 @@ private slots: void testRegistryShortRootNames(); void testRegistry32And64Bit(); void trailingWhitespace(); -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN void fileName(); #endif - void isWritable_data(); + void isWritable_data() { populateWithFormats(); } void isWritable(); void registerFormat(); void setPath(); @@ -168,23 +163,23 @@ private slots: #endif #ifdef QT_BUILD_INTERNAL - void allKeys_data(); + void allKeys_data() { populateWithFormats(); } void allKeys(); - void childGroups_data(); + void childGroups_data() { populateWithFormats(); } void childGroups(); - void childKeys_data(); + void childKeys_data() { populateWithFormats(); } void childKeys(); void testIniParsing_data(); void testIniParsing(); void testEscapes(); void testNormalizedKey_data(); void testNormalizedKey(); - void testVariantTypes_data(); + void testVariantTypes_data() { populateWithFormats(); } void testVariantTypes(); void testMetaTypes_data(); void testMetaTypes(); #endif - void rainersSyncBugOnMac_data(); + void rainersSyncBugOnMac_data() { populateWithFormats(); } void rainersSyncBugOnMac(); void recursionBug(); @@ -198,6 +193,10 @@ private slots: void floatAsQVariant(); void testXdg(); + + void testReadKeys_data(); + void testReadKeys(); + private: void cleanupTestFiles(); @@ -280,16 +279,6 @@ static bool writeCustom3File(QIODevice &device, const QSettings::SettingsMap &ma return true; } -static void populateWithFormats() -{ - QTest::addColumn<QSettings::Format>("format"); - - QTest::newRow("native") << QSettings::NativeFormat; - QTest::newRow("ini") << QSettings::IniFormat; - QTest::newRow("custom1") << QSettings::CustomFormat1; - QTest::newRow("custom2") << QSettings::CustomFormat2; -} - tst_QSettings::tst_QSettings() : m_canWriteNativeSystemSettings(canWriteNativeSystemSettings()) { @@ -349,6 +338,32 @@ void tst_QSettings::cleanupTestFiles() QSettings(QSettings::UserScope, "other.software.org").clear(); QSettings(QSettings::SystemScope, "other.software.org").clear(); #endif +#if defined(Q_OS_WASM) + emscripten::val::global("window")["localStorage"].call<void>("clear"); + if (qstdweb::haveJspi()) { + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::UserScope, "software.org", + "KillerAPP") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::SystemScope, "software.org", + "KillerAPP") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::UserScope, "other.software.org", + "KillerAPP") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::SystemScope, + "other.software.org", "KillerAPP") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::UserScope, "software.org") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::SystemScope, "software.org") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::UserScope, "other.software.org") + .clear(); + QSettings(QSettings::Format::WebIndexedDBFormat, QSettings::SystemScope, + "other.software.org") + .clear(); + } +#endif const QString foo(QLatin1String("foo")); @@ -361,11 +376,6 @@ void tst_QSettings::cleanupTestFiles() Test the constructors and the assignment operator. */ -void tst_QSettings::ctor_data() -{ - populateWithFormats(); -} - void tst_QSettings::ctor() { QFETCH(QSettings::Format, format); @@ -528,10 +538,10 @@ void tst_QSettings::ctor() QSettings settings5(format, QSettings::UserScope, "SoftWare.ORG", "killerApp"); bool caseSensitive = true; -#if defined(Q_OS_MAC) +#if defined(Q_OS_DARWIN) if (format == QSettings::NativeFormat) { // more details in QMacSettingsPrivate::QMacSettingsPrivate(), organization was comify()-ed - caseSensitive = settings5.fileName().contains("SoftWare.ORG");; + caseSensitive = settings5.fileName().contains("SoftWare.ORG"); } else { caseSensitive = pathconf(settings5.fileName().toLatin1().constData(), _PC_CASE_SENSITIVE); } @@ -581,7 +591,7 @@ void tst_QSettings::ctor() 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(settings1.allKeys().size(), 6); QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7); QCOMPARE(settings2.value("alpha/beta/geometry/x").toInt(), 1); @@ -589,7 +599,7 @@ void tst_QSettings::ctor() 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); + QCOMPARE(settings2.allKeys().size(), 6); } { @@ -600,7 +610,7 @@ void tst_QSettings::ctor() 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(settings1.allKeys().size(), 6); } { @@ -609,7 +619,7 @@ void tst_QSettings::ctor() QCoreApplication::instance()->setOrganizationName(""); QCoreApplication::instance()->setApplicationName(""); QSettings settings; -#if defined(Q_OS_MAC) +#if defined(Q_OS_DARWIN) QEXPECT_FAIL("native", "Default settings on Mac are valid, despite organization domain, name, and app name being null", Continue); #endif QCOMPARE(settings.status(), QSettings::AccessError); @@ -624,7 +634,7 @@ void tst_QSettings::ctor() } QSettings settings(format, QSettings::UserScope, "", ""); -#if defined(Q_OS_MAC) +#if defined(Q_OS_DARWIN) QEXPECT_FAIL("native", "Default settings on Mac are valid, despite organization domain, name, and app name being null", Continue); #endif QCOMPARE(settings.status(), QSettings::AccessError); @@ -649,6 +659,50 @@ void tst_QSettings::ctor() } } +#if defined(Q_OS_WASM) +void tst_QSettings::idb() +{ + if (!qstdweb::haveJspi()) + QSKIP("JSPI needed for IndexedDB format"); + + QString systemScopeOrganizationWideFile; + { + QSettings settingsUserScopeAppSpecific(QSettings::Format::WebIndexedDBFormat, + QSettings::UserScope, "software.org", "KillerAPP"); + QSettings settingsUserScopeOrganizationWide(QSettings::Format::WebIndexedDBFormat, + QSettings::UserScope, "software.org"); + QSettings settingsSystemScopeAppSpecific(QSettings::Format::WebIndexedDBFormat, + QSettings::SystemScope, "software.org", + "KillerAPP"); + QSettings settingsSystemScopeOrganizationWide(QSettings::Format::WebIndexedDBFormat, + QSettings::SystemScope, "software.org"); + + settingsSystemScopeOrganizationWide.setValue("testKey", 1); + systemScopeOrganizationWideFile = settingsSystemScopeOrganizationWide.fileName(); + } + + // Emscripten's memfs has a bug that makes a file appear twice in the hashmap. + while (QFile::exists(systemScopeOrganizationWideFile)) { + Q_ASSERT(QFile::remove(systemScopeOrganizationWideFile)); + } + + QEventLoop loop; + QTimer timer; + timer.setInterval(1); + + connect(&timer, &QTimer::timeout, [&loop]() { loop.quit(); }); + timer.start(); + + loop.exec(); + { + QSettings settingsUserScopeAppSpecific(QSettings::Format::WebIndexedDBFormat, + QSettings::UserScope, "software.org", "KillerAPP"); + + QCOMPARE(settingsUserScopeAppSpecific.value("testKey").toInt(), 1); + } +} +#endif // Q_OS_WASM + void tst_QSettings::testByteArray_data() { QTest::addColumn<QByteArray>("data"); @@ -955,7 +1009,7 @@ void tst_QSettings::testIniParsing() if ( settings.status() == QSettings::NoError ) { // else no point proceeding QVariant v = settings.value(key); if (expect.isValid()) - QVERIFY(v.canConvert(expect.type())); + QVERIFY(v.canConvert(expect.metaType())); // check some types so as to give prettier error messages if ( v.typeId() == QMetaType::QString ) { QCOMPARE(v.toString(), expect.toString()); @@ -1183,7 +1237,7 @@ template<int MetaTypeId> static void testMetaTypesHelper(QSettings::Format format) { typedef typename MetaEnumToType<MetaTypeId>::Type Type; - const char *key = QMetaType::typeName(MetaTypeId); + const char *key = QMetaType(MetaTypeId).name(); Type *value = TestValueFactory<MetaTypeId>::create(); QVariant inputVariant = QVariant::fromValue(*value); @@ -1202,8 +1256,8 @@ static void testMetaTypesHelper(QSettings::Format format) QSettings settings(format, scope, organization, applicationName); QVariant outputVariant = settings.value(key); if (MetaTypeId != QMetaType::QVariant) - QVERIFY(outputVariant.canConvert(MetaTypeId)); - if (outputVariant.type() != inputVariant.type()) + QVERIFY(outputVariant.canConvert(QMetaType(MetaTypeId))); + if (outputVariant.typeId() != inputVariant.typeId()) qWarning() << "type mismatch between" << inputVariant << "and" << outputVariant; QCOMPARE(qvariant_cast<Type >(outputVariant), *value); } @@ -1242,7 +1296,7 @@ void tst_QSettings::testMetaTypes_data() #define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \ { \ const char *formatName = QMetaEnum::fromType<QSettings::Format>().valueToKey(formats[i]); \ - const char *typeName = QMetaType::typeName(QMetaType::MetaTypeName); \ + const char *typeName = QMetaType(QMetaType::MetaTypeName).name(); \ QTest::newRow(QString("%1:%2").arg(formatName).arg(typeName).toLatin1().constData()) \ << QSettings::Format(formats[i]) << int(QMetaType::MetaTypeName); \ } @@ -1277,106 +1331,102 @@ FOR_EACH_CORE_METATYPE(RETURN_CREATE_FUNCTION) TypeTestFunctionGetter::get(type)(format); } - -void tst_QSettings::testVariantTypes_data() -{ - populateWithFormats(); -} #endif #ifdef QT_BUILD_INTERNAL void tst_QSettings::testVariantTypes() { -#define testVal(key, val, tp, rtype) \ - { \ - QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); \ - settings1.setValue(key, QVariant::fromValue(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); \ + QFETCH(QSettings::Format, format); + + { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + QVERIFY(!settings.contains("empty")); + QCOMPARE(settings.value("empty"), QVariant()); + + settings.setValue("empty", QVariant()); + QVERIFY(settings.contains("empty")); + QCOMPARE(settings.value("empty"), QVariant()); + + settings.setValue("empty", QVariant(1)); + QVERIFY(settings.contains("empty")); + QCOMPARE(settings.value("empty"), QVariant(1)); + + settings.setValue("empty", QVariant()); + QVERIFY(settings.contains("empty")); + QCOMPARE(settings.value("empty"), QVariant()); + + settings.remove("empty"); + QVERIFY(!settings.contains("empty")); + QCOMPARE(settings.value("empty"), QVariant()); } - typedef QMap<QString, QVariant> TestVariantMap; + auto checker = [format](const char *key, auto value, QMetaType::Type expected) { + { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + settings.setValue(key, QVariant::fromValue(value)); + } + QConfFile::clearCache(); + { + QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP"); + QVariant actual = settings.value(key); + QCOMPARE(actual.metaType().id(), expected); + QCOMPARE(qvariant_cast<decltype(value)>(actual), value); + } + }; +#define testValue(key, supplied, expected) do { \ + checker(key, supplied, QMetaType::expected); \ + if (QTest::currentTestFailed()) \ + return; \ + } while (0) - QFETCH(QSettings::Format, format); + typedef QMap<QString, QVariant> TestVariantMap; TestVariantMap m2; m2.insert("ene", "due"); m2.insert("rike", "fake"); m2.insert("borba", "dorba"); - testVal("key2", m2, TestVariantMap, Map); - - QStringList l2; + testValue("customMap", m2, QVariantMap); - l2 << "ene" << "due" << "@Point(1 2)" << "@fake"; - testVal("key3", l2, QStringList, StringList); + QStringList l2 { "ene", "due", "@Point(1 2)", "@fake" }; + testValue("stringsAt", l2, QStringList); - l2.clear(); - l2 << "ene" << "due" << "rike" << "fake"; - testVal("key3", l2, QStringList, StringList); + l2 = { "ene", "due", "rike", "fake" }; + testValue("strings", l2, QStringList); - QList<QVariant> l3; QDate date = QDate::currentDate(); QTime time = QTime::currentTime(); - l3 << QString("ene") << 10 << QVariant::fromValue(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()); + QList<QVariant> l3 { QString("ene"), 10, QVariant::fromValue(QColor(1, 2, 3)), + QVariant(QRect(1, 2, 3, 4)), QVariant(QSize(4, 56)), QVariant(QPoint(4, 2)), + true, false, date, time }; + testValue("mixedList", l3, QVariantList); + + testValue("string", QString("hello"), QString); + testValue("color", QColor(1, 2, 3), QColor); + testValue("rect", QRect(1, 2, 3, 4), QRect); + testValue("size", QSize(4, 56), QSize); + testValue("point", QPoint(4, 2), QPoint); + testValue("date", date, QDate); + testValue("time", time, QTime); + testValue("byteArray", QByteArray("foo bar"), QByteArray); + + QList<QVariant> l4 { QVariant(m2), QVariant(l2), QVariant(l3) }; + testValue("collectList", l4, QVariantList); - 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); QDateTime dt = QDateTime::currentDateTime(); - dt.setOffsetFromUtc(3600); - testVal("key14", dt, QDateTime, DateTime); + dt.setTimeZone(QTimeZone::fromSecondsAheadOfUtc(3600)); + testValue("dateTime", dt, QDateTime); #if QT_CONFIG(shortcut) // We store key sequences as strings instead of binary variant blob, for improved // readability in the resulting format. - if (format >= QSettings::InvalidFormat) { - testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QKeySequence, KeySequence); - } else { - testVal("keysequence", - QKeySequence(Qt::ControlModifier + Qt::Key_F1).toString(QKeySequence::NativeText), - QString, String); - } + QKeySequence seq(Qt::ControlModifier | Qt::Key_F1); + if (format >= QSettings::InvalidFormat) + testValue("keySequence", seq, QKeySequence); + else + testValue("keySequence", seq.toString(QKeySequence::NativeText), QString); #endif // QT_CONFIG(shortcut) -#undef testVal +#undef testValue } #endif @@ -1766,12 +1816,12 @@ void tst_QSettings::sync() 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); + QCOMPARE(settings2.allKeys().size(), 11); // Now, software.org.ini no longer exists, this is same as another app // clearing all settings. settings1.sync(); - QCOMPARE(settings1.allKeys().count(), 0); + QCOMPARE(settings1.allKeys().size(), 0); // Now "some other app" will change software.org.ini QVERIFY(QFile::rename((userConfDir + "other.software.org.ini").toLatin1(), @@ -1789,7 +1839,7 @@ void tst_QSettings::sync() 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); + QCOMPARE(settings1.allKeys().size(), 11); } void tst_QSettings::syncNonWriteableDir() @@ -1864,11 +1914,6 @@ void tst_QSettings::syncAlternateDataStream() } #endif -void tst_QSettings::setFallbacksEnabled_data() -{ - populateWithFormats(); -} - void tst_QSettings::setFallbacksEnabled() { QFETCH(QSettings::Format, format); @@ -1953,11 +1998,6 @@ void tst_QSettings::setFallbacksEnabled() QVERIFY(!settings1.contains("key 5")); } -void tst_QSettings::testChildKeysAndGroups_data() -{ - populateWithFormats(); -} - void tst_QSettings::testChildKeysAndGroups() { QFETCH(QSettings::Format, format); @@ -2018,6 +2058,14 @@ void tst_QSettings::testChildKeysAndGroups() l.sort(); QCOMPARE(l, QStringList() << "bar" << "foo"); } + +#if defined(Q_OS_WASM) + // WebIndexedDBFormat does not use the cached settings file on creation, but instead always uses + // the file from the indexed DB anew. + if (format == QSettings::Format::WebIndexedDBFormat) + settings1.sync(); +#endif + { QSettings settings3(format, QSettings::UserScope, "software.org", "application"); settings3.setFallbacksEnabled(false); @@ -2095,6 +2143,16 @@ void SettingsThread::run() void tst_QSettings::testThreadSafety() { +#if !QT_CONFIG(thread) + QSKIP("This test requires threads to be enabled."); +#endif // !QT_CONFIG(thread) +#if defined(Q_OS_WASM) + if (!qstdweb::haveJspi()) + QSKIP("Test needs jspi on WASM. Calls are proxied to the main thread from SettingsThreads, " + "which necessitates the use of an event loop to yield to the main loop. Event loops " + "require jspi."); +#endif + SettingsThread threads[NumThreads]; int i, j; @@ -2102,6 +2160,19 @@ void tst_QSettings::testThreadSafety() for (i = 0; i < NumThreads; ++i) threads[i].start(i + 1); + +#if defined(Q_OS_WASM) && QT_CONFIG(thread) + QEventLoop loop; + int remaining = NumThreads; + for (int i = 0; i < NumThreads; ++i) { + QObject::connect(&threads[i], &QThread::finished, this, [&remaining, &loop]() { + if (!--remaining) + loop.quit(); + }); + } + loop.exec(); +#endif // defined(Q_OS_WASM) && QT_CONFIG(thread) + for (i = 0; i < NumThreads; ++i) threads[i].wait(); @@ -2156,20 +2227,17 @@ void tst_QSettings::testNormalizedKey() 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()); - } + { + auto result = QSettingsPrivate::normalizedKey(inKey); + QCOMPARE(result, outKey); + } + { + auto result = QSettingsPrivate::normalizedKey(QUtf8StringView{inKey.toUtf8()}); + QCOMPARE(result, outKey); + } + { + auto result = QSettingsPrivate::normalizedKey(QLatin1String{inKey.toLatin1()}); + QCOMPARE(result, outKey); } } #endif @@ -2355,11 +2423,6 @@ void tst_QSettings::trailingWhitespace() } } -void tst_QSettings::fromFile_data() -{ - populateWithFormats(); -} - void tst_QSettings::fromFile() { QFETCH(QSettings::Format, format); @@ -2381,6 +2444,12 @@ void tst_QSettings::fromFile() QStringList strList = QStringList() << "hope" << "destiny" << "chastity"; +#if !defined(Q_OS_WIN) + auto deleteFile = QScopeGuard([path, oldCur]() { + QFile::remove(path); + QDir::setCurrent(oldCur); + }); +#endif // !defined(Q_OS_WIN) { QSettings settings1(path, format); QVERIFY(settings1.allKeys().isEmpty()); @@ -2416,8 +2485,6 @@ void tst_QSettings::fromFile() QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4); QCOMPARE(settings1.allKeys().size(), 3); } - - QDir::setCurrent(oldCur); } static bool containsSubList(QStringList mom, QStringList son) @@ -2429,11 +2496,6 @@ static bool containsSubList(QStringList mom, QStringList son) return true; } -void tst_QSettings::testArrays_data() -{ - populateWithFormats(); -} - /* Tests beginReadArray(), beginWriteArray(), endArray(), and setArrayIndex(). @@ -2499,17 +2561,17 @@ void tst_QSettings::testArrays() QCOMPARE(settings1.value("ene").toInt(), 2); QCOMPARE(settings1.value("due").toInt(), 3); QCOMPARE(settings1.value("rike").toInt(), 4); - QCOMPARE(settings1.allKeys().count(), 3); + QCOMPARE(settings1.allKeys().size(), 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); + QCOMPARE(settings1.allKeys().size(), 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); + QCOMPARE(settings1.allKeys().size(), 3); settings1.endArray(); settings1.endGroup(); @@ -2559,17 +2621,17 @@ void tst_QSettings::testArrays() QCOMPARE(settings1.value("ene").toInt(), 2); QCOMPARE(settings1.value("due").toInt(), 3); QCOMPARE(settings1.value("rike").toInt(), 4); - QCOMPARE(settings1.allKeys().count(), 3); + QCOMPARE(settings1.allKeys().size(), 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); + QCOMPARE(settings1.allKeys().size(), 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); + QCOMPARE(settings1.allKeys().size(), 3); settings1.endArray(); settings1.endGroup(); @@ -2714,7 +2776,7 @@ static QByteArray iniEscapedKey(const QString &str) static QString iniUnescapedKey(const QByteArray &ba) { QString result; - QSettingsPrivate::iniUnescapedKey(ba, 0, ba.size(), result); + QSettingsPrivate::iniUnescapedKey(ba, result); return result; } @@ -2729,7 +2791,7 @@ static QStringList iniUnescapedStringList(const QByteArray &ba) { QStringList result; QString str; - bool isStringList = QSettingsPrivate::iniUnescapedStringList(ba, 0, ba.size(), str, result); + bool isStringList = QSettingsPrivate::iniUnescapedStringList(ba, str, result); if (!isStringList) result = QStringList(str); return result; @@ -2741,7 +2803,7 @@ QString escapeWeirdChars(const QString &s) QString result; bool escapeNextDigit = false; - for (int i = 0; i < s.length(); ++i) { + for (int i = 0; i < s.size(); ++i) { QChar c = s.at(i); if (c.unicode() < ' ' || c.unicode() > '~' || (escapeNextDigit && c.unicode() >= '0' && c.unicode() <= 'f')) { @@ -2881,11 +2943,6 @@ void tst_QSettings::testEscapes() } #endif -void tst_QSettings::testCaseSensitivity_data() -{ - populateWithFormats(); -} - void tst_QSettings::testCaseSensitivity() { QFETCH(QSettings::Format, format); @@ -2965,7 +3022,7 @@ void tst_QSettings::testCaseSensitivity() } } -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN // Please write a fileName() test for the other platforms void tst_QSettings::fileName() { @@ -3035,11 +3092,6 @@ void tst_QSettings::fileName() } #endif -void tst_QSettings::isWritable_data() -{ - populateWithFormats(); -} - void tst_QSettings::isWritable() { QFETCH(QSettings::Format, format); @@ -3092,13 +3144,6 @@ void tst_QSettings::isWritable() } #ifdef QT_BUILD_INTERNAL -void tst_QSettings::childGroups_data() -{ - populateWithFormats(); -} -#endif - -#ifdef QT_BUILD_INTERNAL void tst_QSettings::childGroups() { QFETCH(QSettings::Format, format); @@ -3168,13 +3213,6 @@ void tst_QSettings::childGroups() #endif #ifdef QT_BUILD_INTERNAL -void tst_QSettings::childKeys_data() -{ - populateWithFormats(); -} -#endif - -#ifdef QT_BUILD_INTERNAL void tst_QSettings::childKeys() { QFETCH(QSettings::Format, format); @@ -3242,13 +3280,6 @@ void tst_QSettings::childKeys() #endif #ifdef QT_BUILD_INTERNAL -void tst_QSettings::allKeys_data() -{ - populateWithFormats(); -} -#endif - -#ifdef QT_BUILD_INTERNAL void tst_QSettings::allKeys() { QFETCH(QSettings::Format, format); @@ -3399,7 +3430,7 @@ void tst_QSettings::setPath() 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) +#if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) && !defined(Q_OS_WASM) TEST_PATH(i == 0, "conf", NativeFormat, UserScope, "alpha") TEST_PATH(i == 0, "conf", NativeFormat, SystemScope, "beta") #endif @@ -3508,11 +3539,6 @@ void tst_QSettings::dontReorderIniKeysNeedlessly() } #endif -void tst_QSettings::rainersSyncBugOnMac_data() -{ - ctor_data(); -} - void tst_QSettings::rainersSyncBugOnMac() { QFETCH(QSettings::Format, format); @@ -3521,6 +3547,12 @@ void tst_QSettings::rainersSyncBugOnMac() if (format == QSettings::NativeFormat) QSKIP("Apple OSes do not support direct reads from and writes to .plist files, due to caching and background syncing. See QTBUG-34899."); #endif +#if defined(Q_OS_WASM) + if (format == QSettings::NativeFormat) + QSKIP("WASM's localStorage backend recognizes no concept of file"); + if (format == QSettings::WebIndexedDBFormat) + QSKIP("WASM's indexedDB backend uses the virtual FS file only as a backing store"); +#endif // Q_OS_WASM QString fileName; @@ -3544,7 +3576,7 @@ void tst_QSettings::rainersSyncBugOnMac() void tst_QSettings::recursionBug() { QPixmap pix(10,10); - pix.fill("blue"); + pix.fill(Qt::blue); { QSettings settings(settingsPath("starrunner.ini"), QSettings::IniFormat); @@ -3591,14 +3623,14 @@ void tst_QSettings::consistentRegistryStorage() } #endif -#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(QT_NO_STANDARDPATHS) +#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WASM) && !defined(QT_NO_STANDARDPATHS) QT_BEGIN_NAMESPACE extern void clearDefaultPaths(); QT_END_NAMESPACE #endif void tst_QSettings::testXdg() { -#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(QT_NO_STANDARDPATHS) +#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(Q_OS_WASM) && !defined(QT_NO_STANDARDPATHS) // Note: The XDG_CONFIG_DIRS test must be done before overriding the system path // by QSettings::setPath/setSystemIniPath (used in cleanupTestFiles()). clearDefaultPaths(); @@ -3663,5 +3695,39 @@ void tst_QSettings::testXdg() #endif } +void tst_QSettings::testReadKeys_data() +{ + QTest::addColumn<QString>("filepath"); + + QTest::newRow("escaped") << ":/qt5settings.ini"; + QTest::newRow("utf-8") << ":/utf8settings.ini"; +} + +void tst_QSettings::testReadKeys() +{ + QFETCH(QString, filepath); + + QSettings settings(filepath, QSettings::IniFormat); + QCOMPARE(settings.status(), QSettings::NoError); + + QVariantMap expectedValues; + expectedValues.insert("Test/BAR", "BAR"); + expectedValues.insert("Test/OST", "OST"); + expectedValues.insert("Test/B\xC3\x84R", "B\xC3\x84R"); // BÄR + expectedValues.insert("Test/\xC3\x96SE", "\xC3\x96SE"); // ÖSE + expectedValues.insert( + "Test/\xD0\xAD\xD1\x82\xD0\xBE/\xD1\x82\xD0\xB5\xD1\x81\xD1\x82", // Это/тест + "\xD0\xAD\xD1\x82\xD0\xBE \xD1\x82\xD0\xB5\xD1\x81\xD1\x82"); // Это тест + expectedValues.insert(".,'%U\xD0\xB0\xD0\xB1\xD0\xB2\xD0\xB3\"\t", ".,'%!@#$"); + expectedValues.insert("\xE2\x99\x9F", "\xE2\x99\x98\xE2\x99\x9A"); // ♟︎ ♘♚ + expectedValues.insert("\xF0\x9F\x8C\x8D", "\xF0\x9F\x8C\x90"); // 🌍 🌐 + + QVariantMap readValues; + for (const auto &key : settings.allKeys()) + readValues.insert(key, settings.value(key)); + + QCOMPARE(readValues, expectedValues); +} + QTEST_MAIN(tst_QSettings) #include "tst_qsettings.moc" diff --git a/tests/auto/corelib/io/qsettings/utf8settings.ini b/tests/auto/corelib/io/qsettings/utf8settings.ini new file mode 100644 index 0000000000..bac010254f --- /dev/null +++ b/tests/auto/corelib/io/qsettings/utf8settings.ini @@ -0,0 +1,11 @@ +[General] +.%2C%27%25Uабвг%22%09=".,'%!@#$" +♟=♘♚ +🌍=🌐 + +[Test] +BAR=BAR +BÄR=BÄR +OST=OST +ÖSE=ÖSE +Это\тест=Это тест |