1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31
32#include <QtCore/QSettings>
33#include <private/qsettings_p.h>
34#include <QtCore/QCoreApplication>
35#include <QtCore/QDateTime>
36#include <QtCore/QtGlobal>
37#include <QtCore/QMetaType>
38#include <QtCore/QString>
39#include <QtCore/QDir>
40#include <QtCore/QThread>
41#include <QtCore/QSysInfo>
42#include <QtGui/QKeySequence>
43
44#include <QtCore>
45#include <QtGui>
46#include "tst_qmetatype.h"
47
48#include <cctype>
49#include <stdlib.h>
50#if defined(Q_OS_WIN) && defined(Q_CC_GNU)
51// need for unlink on mingw
52#include <io.h>
53#endif
54
55#if defined(Q_OS_WIN)
56#include <QtCore/qt_windows.h>
57#ifndef Q_OS_WINRT
58# include <private/qwinregistry_p.h>
59#endif
60#else
61#include <unistd.h>
62#endif
63
64#if defined(Q_OS_DARWIN)
65#include <CoreFoundation/CoreFoundation.h>
66#endif
67
68Q_DECLARE_METATYPE(QSettings::Format)
69
70#ifndef QSETTINGS_P_H_VERSION
71#define QSETTINGS_P_H_VERSION 1
72#endif
73
74QT_FORWARD_DECLARE_CLASS(QSettings)
75
76static inline bool canWriteNativeSystemSettings()
77{
78#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
79 HKEY key;
80 const LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, L"Software", 0, KEY_WRITE, &key);
81 if (result == ERROR_SUCCESS)
82 RegCloseKey(key);
83 else
84 qErrnoWarning(result, "RegOpenKeyEx failed");
85 return result == ERROR_SUCCESS;
86#elif defined(Q_OS_DARWIN)
87 CFStringRef key = CFSTR("canWriteNativeSystemSettings");
88 #define ANY_APP_USER_AND_HOST kCFPreferencesAnyApplication, kCFPreferencesAnyUser, kCFPreferencesAnyHost
89 CFPreferencesSetValue(key, CFSTR("true"), ANY_APP_USER_AND_HOST);
90 if (CFPreferencesSynchronize(ANY_APP_USER_AND_HOST)) {
91 // Cleanup
92 CFPreferencesSetValue(key, 0, ANY_APP_USER_AND_HOST);
93 CFPreferencesSynchronize(ANY_APP_USER_AND_HOST);
94 return true;
95 } else {
96 return false;
97 }
98#else
99 return true;
100#endif
101}
102
103static const char insufficientPermissionSkipMessage[] = "Insufficient permissions for this test.";
104
105class tst_QSettings : public QObject
106{
107 Q_OBJECT
108
109public:
110 tst_QSettings();
111
112public slots:
113 void initTestCase();
114 void cleanup() { cleanupTestFiles(); }
115private slots:
116 void getSetCheck();
117 void ctor_data();
118 void ctor();
119 void beginGroup();
120 void setValue();
121 void remove();
122 void contains();
123 void sync();
124 void syncNonWriteableDir();
125#ifdef Q_OS_WIN
126 void syncAlternateDataStream();
127#endif
128 void setFallbacksEnabled();
129 void setFallbacksEnabled_data();
130 void fromFile_data();
131 void fromFile();
132 void testArrays_data();
133 void testArrays();
134 void testCaseSensitivity_data();
135 void testCaseSensitivity();
136 void testErrorHandling_data();
137 void testErrorHandling();
138 void testChildKeysAndGroups_data();
139 void testChildKeysAndGroups();
140 void testUpdateRequestEvent();
141 void testThreadSafety();
142 void testEmptyData();
143 void testEmptyKey();
144 void testResourceFiles();
145 void testRegistryShortRootNames();
146 void testRegistry32And64Bit();
147 void trailingWhitespace();
148#ifdef Q_OS_MAC
149 void fileName();
150#endif
151 void isWritable_data();
152 void isWritable();
153 void registerFormat();
154 void setPath();
155 void setDefaultFormat();
156 void dontCreateNeedlessPaths();
157#if !defined(Q_OS_WIN) && !defined(QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER)
158 void dontReorderIniKeysNeedlessly();
159#endif
160#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
161 void consistentRegistryStorage();
162#endif
163
164#ifdef QT_BUILD_INTERNAL
165 void allKeys_data();
166 void allKeys();
167 void childGroups_data();
168 void childGroups();
169 void childKeys_data();
170 void childKeys();
171 void setIniCodec();
172 void testIniParsing_data();
173 void testIniParsing();
174 void testEscapes();
175 void testNormalizedKey_data();
176 void testNormalizedKey();
177 void testVariantTypes_data();
178 void testVariantTypes();
179 void testMetaTypes_data();
180 void testMetaTypes();
181#endif
182 void rainersSyncBugOnMac_data();
183 void rainersSyncBugOnMac();
184 void recursionBug();
185
186 void testByteArray_data();
187 void testByteArray();
188 void testByteArrayNativeFormat();
189 void iniCodec();
190 void bom();
191 void embeddedZeroByte_data();
192 void embeddedZeroByte();
193 void spaceAfterComment();
194
195 void testXdg();
196private:
197 void cleanupTestFiles();
198
199 const bool m_canWriteNativeSystemSettings;
200};
201
202// Testing get/set functions
203void tst_QSettings::getSetCheck()
204{
205 QSettings obj1;
206 // bool QSettings::fallbacksEnabled()
207 // void QSettings::setFallbacksEnabled(bool)
208 obj1.setFallbacksEnabled(false);
209 QCOMPARE(false, obj1.fallbacksEnabled());
210 obj1.setFallbacksEnabled(true);
211 QCOMPARE(true, obj1.fallbacksEnabled());
212}
213
214static QString settingsPath(const char *path = nullptr)
215{
216 // Temporary path for files that are specified explicitly in the constructor.
217#ifndef Q_OS_WINRT
218 static const QString tempPath = QDir::tempPath() + QLatin1String("/tst_QSettings");
219#else
220 static const QString tempPath = QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)
221 + QLatin1String("/tst_QSettings");
222#endif
223 return path && *path ? tempPath + QLatin1Char('/') + QLatin1String(path) : tempPath;
224}
225
226static bool readCustom1File(QIODevice &device, QSettings::SettingsMap &map)
227{
228 QDataStream in(&device);
229 quint32 magic;
230 in >> magic;
231 in >> map;
232 return (magic == 0x01010101 && in.status() == QDataStream::Ok);
233}
234
235static bool writeCustom1File(QIODevice &device, const QSettings::SettingsMap &map)
236{
237 QDataStream out(&device);
238 out << quint32(0x01010101);
239 out << map;
240 return out.status() == QDataStream::Ok;
241}
242
243static bool readCustom2File(QIODevice &device, QSettings::SettingsMap &map)
244{
245 QDataStream in(&device);
246 quint64 magic;
247 in >> magic;
248 in >> map;
249 return (magic == Q_UINT64_C(0x0202020202020202) && in.status() == QDataStream::Ok);
250}
251
252static bool writeCustom2File(QIODevice &device, const QSettings::SettingsMap &map)
253{
254 QDataStream out(&device);
255 out << Q_UINT64_C(0x0202020202020202);
256 out << map;
257 return out.status() == QDataStream::Ok;
258}
259
260static bool readCustom3File(QIODevice &device, QSettings::SettingsMap &map)
261{
262 QTextStream in(&device);
263 QString tag;
264 in >> tag;
265 if (tag == "OK") {
266 map.insert(key: "retval", value: "OK");
267 return true;
268 } else {
269 return false;
270 }
271}
272
273static bool writeCustom3File(QIODevice &device, const QSettings::SettingsMap &map)
274{
275 QTextStream out(&device);
276 if (map.value(akey: "retval") != "OK")
277 return false;
278
279 out << "OK";
280 return true;
281}
282
283static void populateWithFormats()
284{
285 QTest::addColumn<QSettings::Format>(name: "format");
286
287 QTest::newRow(dataTag: "native") << QSettings::NativeFormat;
288 QTest::newRow(dataTag: "ini") << QSettings::IniFormat;
289 QTest::newRow(dataTag: "custom1") << QSettings::CustomFormat1;
290 QTest::newRow(dataTag: "custom2") << QSettings::CustomFormat2;
291}
292
293tst_QSettings::tst_QSettings()
294 : m_canWriteNativeSystemSettings(canWriteNativeSystemSettings())
295{
296 QStandardPaths::setTestModeEnabled(true);
297}
298
299void tst_QSettings::initTestCase()
300{
301 if (!m_canWriteNativeSystemSettings)
302 qWarning(msg: "The test is not running with administrative rights. Some tests will be skipped.");
303 QSettings::Format custom1 = QSettings::registerFormat(extension: "custom1", readFunc: readCustom1File, writeFunc: writeCustom1File);
304 QSettings::Format custom2 = QSettings::registerFormat(extension: "custom2", readFunc: readCustom2File, writeFunc: writeCustom2File
305#ifndef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
306 , Qt::CaseInsensitive
307#endif
308 );
309 QCOMPARE(custom1, QSettings::CustomFormat1);
310 QCOMPARE(custom2, QSettings::CustomFormat2);
311
312 cleanupTestFiles();
313}
314
315void tst_QSettings::cleanupTestFiles()
316{
317 QSettings::setPath(format: QSettings::IniFormat, scope: QSettings::SystemScope, path: settingsPath("__system__"));
318 QSettings::setPath(format: QSettings::NativeFormat, scope: QSettings::SystemScope, path: settingsPath("__system__"));
319
320 QSettings::setPath(format: QSettings::IniFormat, scope: QSettings::UserScope, path: settingsPath("__user__"));
321 QSettings::setPath(format: QSettings::NativeFormat, scope: QSettings::UserScope, path: settingsPath("__user__"));
322
323 QDir settingsDir(settingsPath());
324 if (settingsDir.exists())
325 QVERIFY(settingsDir.removeRecursively());
326
327#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
328 QSettings("HKEY_CURRENT_USER\\Software\\software.org", QSettings::NativeFormat).clear();
329 QSettings("HKEY_CURRENT_USER\\Software\\other.software.org", QSettings::NativeFormat).clear();
330 QSettings("HKEY_CURRENT_USER\\Software\\foo", QSettings::NativeFormat).clear();
331 QSettings("HKEY_CURRENT_USER\\Software\\bar", QSettings::NativeFormat).clear();
332 QSettings("HKEY_CURRENT_USER\\Software\\bat", QSettings::NativeFormat).clear();
333 QSettings("HKEY_CURRENT_USER\\Software\\baz", QSettings::NativeFormat).clear();
334 if (m_canWriteNativeSystemSettings) {
335 QSettings("HKEY_LOCAL_MACHINE\\Software\\software.org", QSettings::NativeFormat).clear();
336 QSettings("HKEY_LOCAL_MACHINE\\Software\\other.software.org", QSettings::NativeFormat).clear();
337 QSettings("HKEY_LOCAL_MACHINE\\Software\\foo", QSettings::NativeFormat).clear();
338 QSettings("HKEY_LOCAL_MACHINE\\Software\\bar", QSettings::NativeFormat).clear();
339 QSettings("HKEY_LOCAL_MACHINE\\Software\\bat", QSettings::NativeFormat).clear();
340 QSettings("HKEY_LOCAL_MACHINE\\Software\\baz", QSettings::NativeFormat).clear();
341 }
342#elif defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
343 QSettings(QSettings::UserScope, "software.org", "KillerAPP").clear();
344 QSettings(QSettings::SystemScope, "software.org", "KillerAPP").clear();
345 QSettings(QSettings::UserScope, "other.software.org", "KillerAPP").clear();
346 QSettings(QSettings::SystemScope, "other.software.org", "KillerAPP").clear();
347 QSettings(QSettings::UserScope, "software.org").clear();
348 QSettings(QSettings::SystemScope, "software.org").clear();
349 QSettings(QSettings::UserScope, "other.software.org").clear();
350 QSettings(QSettings::SystemScope, "other.software.org").clear();
351#endif
352
353 const QString foo(QLatin1String("foo"));
354
355#if defined(Q_OS_WINRT)
356 QSettings(foo, QSettings::NativeFormat).clear();
357 QFile fooFile(QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) + QLatin1Char('/') + foo);
358#else
359 QFile fooFile(foo);
360#endif
361 if (fooFile.exists())
362 QVERIFY2(fooFile.remove(), qPrintable(fooFile.errorString()));
363}
364
365/*
366 Test the constructors and the assignment operator.
367*/
368
369void tst_QSettings::ctor_data()
370{
371 populateWithFormats();
372}
373
374void tst_QSettings::ctor()
375{
376 QFETCH(QSettings::Format, format);
377
378 if (!m_canWriteNativeSystemSettings && format == QSettings::NativeFormat)
379 QSKIP(insufficientPermissionSkipMessage);
380
381 {
382 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP");
383 QSettings settings2(format, QSettings::UserScope, "software.org");
384 QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP");
385 QSettings settings4(format, QSettings::SystemScope, "software.org");
386
387 QSettings settings5(format, QSettings::UserScope, "software.org", "KillerAPP");
388 QSettings settings6(format, QSettings::UserScope, "software.org");
389 QSettings settings7(format, QSettings::SystemScope, "software.org", "KillerAPP");
390 QSettings settings8(format, QSettings::SystemScope, "software.org");
391
392 // test QSettings::format() while we're at it
393 QCOMPARE(settings1.format(), format);
394 QCOMPARE(settings2.format(), format);
395 QCOMPARE(settings3.format(), format);
396 QCOMPARE(settings4.format(), format);
397
398 // test QSettings::scope() while we're at it
399 QCOMPARE(settings1.scope(), QSettings::UserScope);
400 QCOMPARE(settings2.scope(), QSettings::UserScope);
401 QCOMPARE(settings3.scope(), QSettings::SystemScope);
402 QCOMPARE(settings4.scope(), QSettings::SystemScope);
403
404 // test QSettings::organizationName() while we're at it
405 QCOMPARE(settings1.organizationName(), QLatin1String("software.org"));
406 QCOMPARE(settings2.organizationName(), QLatin1String("software.org"));
407 QCOMPARE(settings3.organizationName(), QLatin1String("software.org"));
408 QCOMPARE(settings4.organizationName(), QLatin1String("software.org"));
409
410 // test QSettings::applicationName() while we're at it
411 QCOMPARE(settings1.applicationName(), QString("KillerAPP"));
412 QVERIFY(settings2.applicationName().isEmpty());
413 QCOMPARE(settings3.applicationName(), QLatin1String("KillerAPP"));
414 QVERIFY(settings4.applicationName().isEmpty());
415
416 /*
417 Go forwards.
418 */
419 settings4.setValue(key: "key 1", value: QString("doodah"));
420 QCOMPARE(settings1.value("key 1").toString(), QString("doodah"));
421 QCOMPARE(settings2.value("key 1").toString(), QString("doodah"));
422 QCOMPARE(settings3.value("key 1").toString(), QString("doodah"));
423 QCOMPARE(settings4.value("key 1").toString(), QString("doodah"));
424
425 settings3.setValue(key: "key 1", value: QString("blah"));
426 QCOMPARE(settings1.value("key 1").toString(), QString("blah"));
427 QCOMPARE(settings2.value("key 1").toString(), QString("doodah"));
428 QCOMPARE(settings3.value("key 1").toString(), QString("blah"));
429 QCOMPARE(settings4.value("key 1").toString(), QString("doodah"));
430
431 settings2.setValue(key: "key 1", value: QString("whoa"));
432 QCOMPARE(settings1.value("key 1").toString(), QString("whoa"));
433 QCOMPARE(settings2.value("key 1").toString(), QString("whoa"));
434 QCOMPARE(settings3.value("key 1").toString(), QString("blah"));
435 QCOMPARE(settings4.value("key 1").toString(), QString("doodah"));
436
437 settings1.setValue(key: "key 1", value: QString("gurgle"));
438 QCOMPARE(settings1.value("key 1").toString(), QString("gurgle"));
439 QCOMPARE(settings2.value("key 1").toString(), QString("whoa"));
440 QCOMPARE(settings3.value("key 1").toString(), QString("blah"));
441 QCOMPARE(settings4.value("key 1").toString(), QString("doodah"));
442
443 /*
444 Test the copies.
445 */
446 QCOMPARE(settings5.value("key 1").toString(), settings1.value("key 1").toString());
447 QCOMPARE(settings6.value("key 1").toString(), settings2.value("key 1").toString());
448 QCOMPARE(settings7.value("key 1").toString(), settings3.value("key 1").toString());
449 QCOMPARE(settings8.value("key 1").toString(), settings4.value("key 1").toString());
450
451 /*
452 Go backwards.
453 */
454
455 settings2.setValue(key: "key 1", value: QString("bilboh"));
456 QCOMPARE(settings1.value("key 1").toString(), QString("gurgle"));
457 QCOMPARE(settings2.value("key 1").toString(), QString("bilboh"));
458 QCOMPARE(settings3.value("key 1").toString(), QString("blah"));
459 QCOMPARE(settings4.value("key 1").toString(), QString("doodah"));
460
461 settings3.setValue(key: "key 1", value: QString("catha"));
462 QCOMPARE(settings1.value("key 1").toString(), QString("gurgle"));
463 QCOMPARE(settings2.value("key 1").toString(), QString("bilboh"));
464 QCOMPARE(settings3.value("key 1").toString(), QString("catha"));
465 QCOMPARE(settings4.value("key 1").toString(), QString("doodah"));
466
467 settings4.setValue(key: "key 1", value: QString("quirko"));
468 QCOMPARE(settings1.value("key 1").toString(), QString("gurgle"));
469 QCOMPARE(settings2.value("key 1").toString(), QString("bilboh"));
470 QCOMPARE(settings3.value("key 1").toString(), QString("catha"));
471 QCOMPARE(settings4.value("key 1").toString(), QString("quirko"));
472
473 /*
474 Test the copies again.
475 */
476 QCOMPARE(settings5.value("key 1").toString(), settings1.value("key 1").toString());
477 QCOMPARE(settings6.value("key 1").toString(), settings2.value("key 1").toString());
478 QCOMPARE(settings7.value("key 1").toString(), settings3.value("key 1").toString());
479 QCOMPARE(settings8.value("key 1").toString(), settings4.value("key 1").toString());
480
481 /*
482 "General" is a problem key for .ini files.
483 */
484 settings1.setValue(key: "General", value: 1);
485 settings1.setValue(key: "%General", value: 2);
486 settings1.setValue(key: "alpha", value: 3);
487 settings1.setValue(key: "General/alpha", value: 4);
488 settings1.setValue(key: "%General/alpha", value: 5);
489 settings1.setValue(key: "alpha/General", value: 6);
490 settings1.setValue(key: "alpha/%General", value: 7);
491 settings1.setValue(key: "General/General", value: 8);
492 settings1.setValue(key: "General/%General", value: 9);
493 settings1.setValue(key: "%General/General", value: 10);
494 settings1.setValue(key: "%General/%General", value: 11);
495 }
496
497 {
498 /*
499 Test that the data was stored on disk after all instances
500 of QSettings are destroyed.
501 */
502
503 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP");
504 QSettings settings2(format, QSettings::UserScope, "software.org");
505 QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP");
506 QSettings settings4(format, QSettings::SystemScope, "software.org");
507
508 QCOMPARE(settings1.value("key 1").toString(), QString("gurgle"));
509 QCOMPARE(settings2.value("key 1").toString(), QString("bilboh"));
510 QCOMPARE(settings3.value("key 1").toString(), QString("catha"));
511 QCOMPARE(settings4.value("key 1").toString(), QString("quirko"));
512
513 /*
514 Test problem keys.
515 */
516
517 QCOMPARE(settings1.value("General").toInt(), 1);
518 QCOMPARE(settings1.value("%General").toInt(), 2);
519 QCOMPARE(settings1.value("alpha").toInt(), 3);
520 QCOMPARE(settings1.value("General/alpha").toInt(), 4);
521 QCOMPARE(settings1.value("%General/alpha").toInt(), 5);
522 QCOMPARE(settings1.value("alpha/General").toInt(), 6);
523 QCOMPARE(settings1.value("alpha/%General").toInt(), 7);
524 QCOMPARE(settings1.value("General/General").toInt(), 8);
525 QCOMPARE(settings1.value("General/%General").toInt(), 9);
526 QCOMPARE(settings1.value("%General/General").toInt(), 10);
527 QCOMPARE(settings1.value("%General/%General").toInt(), 11);
528
529 /*
530 Test that the organization and product parameters are
531 case-insensitive on case-insensitive file systems.
532 */
533 QSettings settings5(format, QSettings::UserScope, "SoftWare.ORG", "killerApp");
534
535 bool caseSensitive = true;
536#if defined(Q_OS_MAC)
537 if (format == QSettings::NativeFormat) {
538 // more details in QMacSettingsPrivate::QMacSettingsPrivate(), organization was comify()-ed
539 caseSensitive = settings5.fileName().contains("SoftWare.ORG");;
540 } else {
541 caseSensitive = pathconf(settings5.fileName().toLatin1().constData(), _PC_CASE_SENSITIVE);
542 }
543#elif defined(Q_OS_WIN32) || defined(Q_OS_WINRT)
544 caseSensitive = false;
545#endif
546 if (caseSensitive)
547 QVERIFY(!settings5.contains("key 1"));
548 else
549 QVERIFY(settings5.contains("key 1"));
550 }
551
552 {
553 QSettings settings1(settingsPath("custom/custom.conf"), QSettings::IniFormat);
554 settings1.beginGroup(prefix: "alpha/beta");
555 settings1.setValue(key: "geometry", value: -7);
556 settings1.setValue(key: "geometry/x", value: 1);
557 settings1.setValue(key: "geometry/y", value: 2);
558 QSettings settings2(settingsPath("custom/custom.conf"), QSettings::IniFormat);
559 settings1.setValue(key: "geometry/width", value: 3);
560 settings2.setValue(key: "alpha/beta/geometry/height", value: 4);
561 settings2.setValue(key: "alpha/gamma/splitter", value: 5);
562 settings1.endGroup();
563
564 // test QSettings::scope() while we're at it
565 QCOMPARE(settings1.scope(), QSettings::UserScope);
566
567 // test QSettings::organizationName() while we're at it
568 QVERIFY(settings1.organizationName().isEmpty());
569
570 // test QSettings::applicationName() while we're at it
571 QVERIFY(settings1.organizationName().isEmpty());
572
573 QSettings settings3(settingsPath("custom/custom2.conf"), QSettings::IniFormat);
574 settings3.beginGroup(prefix: "doodley/beta");
575 settings3.setValue(key: "geometry", value: -7);
576 settings3.setValue(key: "geometry/x", value: 1);
577 settings3.setValue(key: "geometry/y", value: 2);
578 settings3.setValue(key: "geometry/width", value: 3);
579 settings3.setValue(key: "geometry/height", value: 4);
580 settings3.endGroup();
581 settings3.setValue(key: "alpha/gamma/splitter", value: 5);
582
583 QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7);
584 QCOMPARE(settings1.value("alpha/beta/geometry/x").toInt(), 1);
585 QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2);
586 QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3);
587 QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4);
588 QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 5);
589 QCOMPARE(settings1.allKeys().count(), 6);
590
591 QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7);
592 QCOMPARE(settings2.value("alpha/beta/geometry/x").toInt(), 1);
593 QCOMPARE(settings2.value("alpha/beta/geometry/y").toInt(), 2);
594 QCOMPARE(settings2.value("alpha/beta/geometry/width").toInt(), 3);
595 QCOMPARE(settings2.value("alpha/beta/geometry/height").toInt(), 4);
596 QCOMPARE(settings2.value("alpha/gamma/splitter").toInt(), 5);
597 QCOMPARE(settings2.allKeys().count(), 6);
598 }
599
600 {
601 QSettings settings1(settingsPath("custom/custom.conf"), QSettings::IniFormat);
602 QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7);
603 QCOMPARE(settings1.value("alpha/beta/geometry/x").toInt(), 1);
604 QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2);
605 QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3);
606 QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4);
607 QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 5);
608 QCOMPARE(settings1.allKeys().count(), 6);
609 }
610
611 {
612 // QSettings's default constructor is native by default
613 if (format == QSettings::NativeFormat) {
614 QCoreApplication::instance()->setOrganizationName("");
615 QCoreApplication::instance()->setApplicationName("");
616 QSettings settings;
617#if defined(Q_OS_MAC) || defined(Q_OS_WINRT)
618 QEXPECT_FAIL("native", "Default settings on Mac/WinRT are valid, despite organization domain, name, and app name being null", Continue);
619#endif
620 QCOMPARE(settings.status(), QSettings::AccessError);
621 QCoreApplication::instance()->setOrganizationName("software.org");
622 QCoreApplication::instance()->setApplicationName("KillerAPP");
623 QSettings settings2;
624 QCOMPARE(settings2.status(), QSettings::NoError);
625 QSettings settings3("software.org", "KillerAPP");
626 QCOMPARE(settings2.fileName(), settings3.fileName());
627 QCoreApplication::instance()->setOrganizationName("");
628 QCoreApplication::instance()->setApplicationName("");
629 }
630
631 QSettings settings(format, QSettings::UserScope, "", "");
632#if defined(Q_OS_MAC) || defined(Q_OS_WINRT)
633 QEXPECT_FAIL("native", "Default settings on Mac/WinRT are valid, despite organization domain, name, and app name being null", Continue);
634#endif
635 QCOMPARE(settings.status(), QSettings::AccessError);
636 QSettings settings2(format, QSettings::UserScope, "software.org", "KillerAPP");
637 QCOMPARE(settings2.status(), QSettings::NoError);
638
639 // test QSettings::format() while we're at it
640 QCOMPARE(settings.format(), format);
641 QCOMPARE(settings2.format(), format);
642
643 // test QSettings::scope() while we're at it
644 QCOMPARE(settings.scope(), QSettings::UserScope);
645 QCOMPARE(settings2.scope(), QSettings::UserScope);
646
647 // test QSettings::organizationName() while we're at it
648 QVERIFY(settings.organizationName().isEmpty());
649 QCOMPARE(settings2.organizationName(), QLatin1String("software.org"));
650
651 // test QSettings::applicationName() while we're at it
652 QVERIFY(settings.applicationName().isEmpty());
653 QCOMPARE(settings2.applicationName(), QLatin1String("KillerAPP"));
654 }
655}
656
657void tst_QSettings::testByteArray_data()
658{
659 QTest::addColumn<QByteArray>(name: "data");
660
661 QByteArray bytes("Hello world!");
662
663 QTest::newRow(dataTag: "latin1") << bytes;
664#ifndef QT_NO_COMPRESS
665 QTest::newRow(dataTag: "compressed") << qCompress(data: bytes);
666#endif
667}
668
669void tst_QSettings::testByteArray()
670{
671 QFETCH(QByteArray, data);
672
673 // write
674 {
675 QSettings settings("QtProject", "tst_qsettings");
676 settings.setValue(key: "byteArray", value: data);
677 }
678 // read
679 {
680 QSettings settings("QtProject", "tst_qsettings");
681 QByteArray ret = settings.value(key: "byteArray", defaultValue: data).toByteArray();
682 QCOMPARE(ret, data);
683 }
684}
685
686void tst_QSettings::testByteArrayNativeFormat()
687{
688#ifndef Q_OS_MACOS
689 QSKIP("This test is specific to macOS plist reading.");
690#else
691 QSettings settings(":/resourcefile6.plist", QSettings::NativeFormat);
692 QCOMPARE(settings.value("passwordData"), QVariant(QByteArray::fromBase64("RBxVAAsDVsO/")));
693#endif
694}
695
696void tst_QSettings::iniCodec()
697{
698 {
699 QSettings settings("QtProject", "tst_qsettings");
700 settings.setIniCodec("cp1251");
701 QByteArray ba;
702 ba.resize(size: 256);
703 for (int i = 0; i < ba.size(); i++)
704 ba[i] = i;
705 settings.setValue(key: "array",value: ba);
706 }
707 {
708 QSettings settings("QtProject", "tst_qsettings");
709 settings.setIniCodec("cp1251");
710 QByteArray ba = settings.value(key: "array").toByteArray();
711 QCOMPARE(ba.size(), 256);
712 for (int i = 0; i < ba.size(); i++)
713 QCOMPARE((uchar)ba.at(i), (uchar)i);
714 }
715
716}
717
718void tst_QSettings::bom()
719{
720 QSettings s(":/bom.ini", QSettings::IniFormat);
721 QStringList allkeys = s.allKeys();
722 QCOMPARE(allkeys.size(), 2);
723 QVERIFY(allkeys.contains("section1/foo1"));
724 QVERIFY(allkeys.contains("section2/foo2"));
725}
726
727void tst_QSettings::embeddedZeroByte_data()
728{
729 QTest::addColumn<QVariant>(name: "value");
730
731 QByteArray bytes("hello\0world", 11);
732
733 QTest::newRow(dataTag: "bytearray\\0") << QVariant(bytes);
734 QTest::newRow(dataTag: "string\\0") << QVariant(QString::fromLatin1(str: bytes.data(), size: bytes.size()));
735
736 bytes = QByteArray("@String(");
737
738 QTest::newRow(dataTag: "@bytearray") << QVariant(bytes);
739 QTest::newRow(dataTag: "@string") << QVariant(QString(bytes));
740
741 bytes = QByteArray("@String(\0test", 13);
742
743 QTest::newRow(dataTag: "@bytearray\\0") << QVariant(bytes);
744 QTest::newRow(dataTag: "@string\\0") << QVariant(QString::fromLatin1(str: bytes.data(), size: bytes.size()));
745
746 bytes = QByteArray("@\xdd\x7d", 3);
747 QTest::newRow(dataTag: "@-prefixed data") << QVariant(bytes);
748 QTest::newRow(dataTag: "@-prefixed data as string") << QVariant(QString::fromLatin1(str: bytes.data(), size: bytes.size()));
749}
750
751void tst_QSettings::embeddedZeroByte()
752{
753 QFETCH(QVariant, value);
754 {
755 QSettings settings("QtProject", "tst_qsettings");
756 settings.setValue(key: QTest::currentDataTag(), value);
757 }
758 {
759 QSettings settings("QtProject", "tst_qsettings");
760 QVariant outValue = settings.value(key: QTest::currentDataTag());
761
762 switch (value.type()) {
763 case QVariant::ByteArray:
764 QCOMPARE(outValue.toByteArray(), value.toByteArray());
765 break;
766 case QVariant::String:
767 QCOMPARE(outValue.toString(), value.toString());
768 break;
769 default:
770 Q_UNREACHABLE();
771 }
772
773 if (value.toByteArray().contains(c: QChar::Null))
774 QVERIFY(outValue.toByteArray().contains(QChar::Null));
775 }
776}
777
778void tst_QSettings::spaceAfterComment()
779{
780 QSettings settings(QFINDTESTDATA("withcomments.ini"), QSettings::IniFormat);
781 QCOMPARE(settings.status(), QSettings::NoError);
782
783 QStringList groups = settings.childGroups();
784 QVERIFY(groups.contains("Regular"));
785 QVERIFY(groups.contains("WithSpaces"));
786 QVERIFY(groups.contains("WithTab"));
787 QVERIFY(groups.contains("SpacedGroup"));
788
789 settings.beginGroup(prefix: "Regular");
790 QCOMPARE(settings.value("bar"), QVariant(2));
791 settings.endGroup();
792
793 settings.beginGroup(prefix: "WithSpaces");
794 QCOMPARE(settings.value("bar"), QVariant(4));
795 settings.endGroup();
796
797 settings.beginGroup(prefix: "WithTab");
798 QCOMPARE(settings.value("bar"), QVariant(6));
799 settings.endGroup();
800
801 settings.beginGroup(prefix: "SpacedGroup");
802 QCOMPARE(settings.value("bar"), QVariant(7));
803 settings.endGroup();
804}
805
806void tst_QSettings::testErrorHandling_data()
807{
808 QTest::addColumn<int>(name: "filePerms"); // -1 means file should not exist
809 QTest::addColumn<int>(name: "dirPerms");
810 QTest::addColumn<int>(name: "statusAfterCtor");
811 QTest::addColumn<bool>(name: "shouldBeEmpty");
812 QTest::addColumn<int>(name: "statusAfterGet");
813 QTest::addColumn<int>(name: "statusAfterSetAndSync");
814
815 // file dir afterCtor empty afterGet afterSetAndSync
816 QTest::newRow(dataTag: "0600 0700") << 0600 << 0700 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError;
817
818 QTest::newRow(dataTag: "0400 0700") << 0400 << 0700 << (int)QSettings::NoError
819 << false << (int)QSettings::NoError << (int)QSettings::AccessError;
820 QTest::newRow(dataTag: "0200 0700") << 0200 << 0700 << (int)QSettings::AccessError
821 << true << (int)QSettings::AccessError << (int)QSettings::AccessError;
822
823 QTest::newRow(dataTag: " -1 0700") << -1 << 0700 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::NoError;
824
825 QTest::newRow(dataTag: " -1 0000") << -1 << 0000 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError;
826 QTest::newRow(dataTag: " -1 0100") << -1 << 0100 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError;
827 QTest::newRow(dataTag: "0600 0100") << 0600 << 0100 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError;
828 QTest::newRow(dataTag: " -1 0300") << -1 << 0300 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::NoError;
829 QTest::newRow(dataTag: "0600 0300") << 0600 << 0300 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError;
830 QTest::newRow(dataTag: " -1 0500") << -1 << 0500 << (int)QSettings::NoError << true << (int)QSettings::NoError << (int)QSettings::AccessError;
831 QTest::newRow(dataTag: "0600 0500") << 0600 << 0500 << (int)QSettings::NoError << false << (int)QSettings::NoError << (int)QSettings::NoError;
832}
833
834void tst_QSettings::testErrorHandling()
835{
836#ifdef Q_OS_WIN
837 QSKIP("Windows doesn't support most file modes, including read-only directories, so this test is moot.");
838#elif defined(Q_OS_UNIX)
839#if !defined(Q_OS_VXWORKS) // VxWorks does not have users/groups
840 if (::getuid() == 0)
841#endif
842 QSKIP("Running this test as root doesn't work, since file perms do not bother him");
843#else
844 QFETCH(int, filePerms);
845 QFETCH(int, dirPerms);
846 QFETCH(int, statusAfterCtor);
847 QFETCH(bool, shouldBeEmpty);
848 QFETCH(int, statusAfterGet);
849 QFETCH(int, statusAfterSetAndSync);
850
851 system(QString("chmod 700 %1 2>/dev/null").arg(settingsPath("someDir")).toLatin1());
852 system(QString("chmod -R u+rwx %1 2>/dev/null").arg(settingsPath("someDir")).toLatin1());
853 system(QString("rm -fr %1").arg(settingsPath("someDir")).toLatin1());
854
855 // prepare a file with some settings
856 if (filePerms != -1) {
857 QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat);
858 QCOMPARE((int) settings.status(), (int) QSettings::NoError);
859
860 settings.beginGroup("alpha/beta");
861 settings.setValue("geometry", -7);
862 settings.setValue("geometry/x", 1);
863 settings.setValue("geometry/y", 2);
864 settings.setValue("geometry/width", 3);
865 settings.setValue("geometry/height", 4);
866 settings.endGroup();
867 settings.setValue("alpha/gamma/splitter", 5);
868 } else {
869 system(QString("mkdir -p %1").arg(settingsPath("someDir")).toLatin1());
870 }
871
872 if (filePerms != -1) {
873 system(QString("chmod %1 %2")
874 .arg(QString::number(filePerms, 8))
875 .arg(settingsPath("someDir/someSettings.ini"))
876 .toLatin1());
877 }
878 system(QString("chmod %1 %2")
879 .arg(QString::number(dirPerms, 8))
880 .arg(settingsPath("someDir"))
881 .toLatin1());
882
883 // the test
884 {
885 QConfFile::clearCache();
886 QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat);
887 QCOMPARE((int)settings.status(), statusAfterCtor);
888 if (shouldBeEmpty) {
889 QCOMPARE(settings.allKeys().count(), 0);
890 } else {
891 QVERIFY(settings.allKeys().count() > 0);
892 }
893 settings.value("alpha/beta/geometry");
894 QCOMPARE((int)settings.status(), statusAfterGet);
895 settings.setValue("alpha/beta/geometry", 100);
896 QCOMPARE((int)settings.status(), statusAfterGet);
897 QCOMPARE(settings.value("alpha/beta/geometry").toInt(), 100);
898 settings.sync();
899 QCOMPARE(settings.value("alpha/beta/geometry").toInt(), 100);
900 QCOMPARE((int)settings.status(), statusAfterSetAndSync);
901 }
902#endif // !Q_OS_WIN
903}
904
905Q_DECLARE_METATYPE(QSettings::Status)
906
907#ifdef QT_BUILD_INTERNAL
908void tst_QSettings::testIniParsing_data()
909{
910 QTest::addColumn<QByteArray>(name: "inicontent");
911 QTest::addColumn<QString>(name: "key");
912 QTest::addColumn<QVariant>(name: "expect");
913 QTest::addColumn<QSettings::Status>(name: "status");
914
915 // Test "forgiving" parsing of entries not terminated with newline or unterminated strings
916 QTest::newRow(dataTag: "good1") << QByteArray("v=1\n") << "v" << QVariant(1) << QSettings::NoError;
917 QTest::newRow(dataTag: "good2") << QByteArray("v=1\\\n2") << "v" << QVariant(12) << QSettings::NoError;
918 QTest::newRow(dataTag: "good3") << QByteArray("v=1\\\r2") << "v" << QVariant(12) << QSettings::NoError;
919 QTest::newRow(dataTag: "good4") << QByteArray("v=1\\\n\r2") << "v" << QVariant(12) << QSettings::NoError;
920 QTest::newRow(dataTag: "good5") << QByteArray("v=1\\\r\n2") << "v" << QVariant(12) << QSettings::NoError;
921 QTest::newRow(dataTag: "good6") << QByteArray("v \t = \t 1\\\r\n2") << "v" << QVariant(12) << QSettings::NoError;
922 QTest::newRow(dataTag: "garbage1") << QByteArray("v") << "v" << QVariant() << QSettings::FormatError;
923 QTest::newRow(dataTag: "nonterm1") << QByteArray("v=str") << "v" << QVariant("str") << QSettings::NoError;
924 QTest::newRow(dataTag: "nonterm2") << QByteArray("v=\"str\"") << "v" << QVariant("str") << QSettings::NoError;
925 QTest::newRow(dataTag: "nonterm3") << QByteArray("v=\"str") << "v" << QVariant("str") << QSettings::NoError;
926 QTest::newRow(dataTag: "nonterm4") << QByteArray("v=\\") << "v" << QVariant("") << QSettings::NoError;
927 QTest::newRow(dataTag: "nonterm5") << QByteArray("u=s\nv=\"str") << "v" << QVariant("str") << QSettings::NoError;
928 QTest::newRow(dataTag: "nonterm6") << QByteArray("v=\"str\nw=ok") << "v" << QVariant("str\nw=ok") << QSettings::NoError;
929 QTest::newRow(dataTag: "nonterm7") << QByteArray("v=") << "v" << QVariant("") << QSettings::NoError;
930 QTest::newRow(dataTag: "nonterm8") << QByteArray("v=\"str\njnk") << "v" << QVariant("str\njnk") << QSettings::NoError;
931 QTest::newRow(dataTag: "nonterm9") << QByteArray("v=1\\") << "v" << QVariant(1) << QSettings::NoError;
932 QTest::newRow(dataTag: "nonterm10") << QByteArray("v=1\\\n") << "v" << QVariant(1) << QSettings::NoError;
933 QTest::newRow(dataTag: "nonterm11") << QByteArray("v=1\\\r") << "v" << QVariant(1) << QSettings::NoError;
934 QTest::newRow(dataTag: "nonterm12") << QByteArray("v=1\\\n\r") << "v" << QVariant(1) << QSettings::NoError;
935 QTest::newRow(dataTag: "nonterm13") << QByteArray("v=1\\\r\n") << "v" << QVariant(1) << QSettings::NoError;
936 QTest::newRow(dataTag: "nonterm14") << QByteArray("v=1\\\n\nx=2") << "v" << QVariant(1) << QSettings::NoError;
937 QTest::newRow(dataTag: "nonterm15") << QByteArray("v=1\\\r\rx=2") << "v" << QVariant(1) << QSettings::NoError;
938 QTest::newRow(dataTag: "nonterm16") << QByteArray("v=1\\\n\n\nx=2") << "v" << QVariant(1) << QSettings::NoError;
939 QTest::newRow(dataTag: "nonterm17") << QByteArray("; foo\nv=1") << "v" << QVariant(1) << QSettings::NoError;
940 QTest::newRow(dataTag: "nonterm18") << QByteArray("; foo\n\nv=1") << "v" << QVariant(1) << QSettings::NoError;
941 QTest::newRow(dataTag: "nonterm19") << QByteArray("\nv=1;foo") << "v" << QVariant(1) << QSettings::NoError;
942 QTest::newRow(dataTag: "nonterm20") << QByteArray("v=x ") << "v" << QVariant("x") << QSettings::NoError;
943 QTest::newRow(dataTag: "nonterm21") << QByteArray("v=x ;") << "v" << QVariant("x") << QSettings::NoError;
944}
945#endif
946
947#ifdef QT_BUILD_INTERNAL
948void tst_QSettings::testIniParsing()
949{
950 qRegisterMetaType<QSettings::Status>(typeName: "QSettings::Status");
951
952 QDir dir(settingsPath());
953 QVERIFY(dir.mkpath("someDir"));
954 QFile f(dir.path()+"/someDir/someSettings.ini");
955
956 QFETCH(QByteArray, inicontent);
957 QFETCH(QString, key);
958 QFETCH(QVariant, expect);
959 QFETCH(QSettings::Status, status);
960
961 QVERIFY(f.open(QFile::WriteOnly));
962 f.write(data: inicontent);
963 f.close();
964
965 QConfFile::clearCache();
966 QSettings settings(settingsPath("someDir/someSettings.ini"), QSettings::IniFormat);
967
968 if ( settings.status() == QSettings::NoError ) { // else no point proceeding
969 QVariant v = settings.value(key);
970 QVERIFY(v.canConvert(expect.type()));
971 // check some types so as to give prettier error messages
972 if ( v.type() == QVariant::String ) {
973 QCOMPARE(v.toString(), expect.toString());
974 } else if ( v.type() == QVariant::Int ) {
975 QCOMPARE(v.toInt(), expect.toInt());
976 } else {
977 QCOMPARE(v, expect);
978 }
979 }
980
981 QCOMPARE(settings.status(), status);
982}
983#endif
984
985/*
986 Tests beginGroup(), endGroup(), and group().
987*/
988void tst_QSettings::beginGroup()
989{
990 QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP");
991 QSettings settings2(QSettings::UserScope, "software.org", "KillerAPP");
992
993 /*
994 Let's start with some back and forthing.
995 */
996
997 settings1.beginGroup(prefix: "alpha");
998 QCOMPARE(settings1.group(), QString("alpha"));
999 settings1.endGroup();
1000 QCOMPARE(settings1.group(), QString());
1001 settings1.beginGroup(prefix: "/beta");
1002 QCOMPARE(settings1.group(), QString("beta"));
1003 settings1.endGroup();
1004 QCOMPARE(settings1.group(), QString());
1005
1006 settings1.beginGroup(prefix: "///gamma//");
1007 QCOMPARE(settings1.group(), QString("gamma"));
1008 settings1.endGroup();
1009 QCOMPARE(settings1.group(), QString());
1010
1011 settings1.setValue(key: "geometry", value: 5);
1012 QCOMPARE(settings1.value("geometry").toInt(), 5);
1013 QCOMPARE(settings1.value("/geometry///").toInt(), 5);
1014 QCOMPARE(settings2.value("geometry").toInt(), 5);
1015 QCOMPARE(settings2.value("/geometry///").toInt(), 5);
1016
1017 /*
1018 OK, now start for real.
1019 */
1020
1021 settings1.beginGroup(prefix: "alpha");
1022 QCOMPARE(settings1.group(), QString("alpha"));
1023 settings1.setValue(key: "geometry", value: 66);
1024 QCOMPARE(settings1.value("geometry").toInt(), 66);
1025 QCOMPARE(settings2.value("geometry").toInt(), 5);
1026 QCOMPARE(settings2.value("alpha/geometry").toInt(), 66);
1027
1028 QSettings settings3(QSettings::UserScope, "software.org", "KillerAPP");
1029 settings3.beginGroup(prefix: "alpha");
1030 QCOMPARE(settings3.value("geometry").toInt(), 66);
1031
1032 settings1.beginGroup(prefix: "/beta///");
1033 QCOMPARE(settings1.group(), QString("alpha/beta"));
1034 settings1.setValue(key: "geometry", value: 777);
1035 QCOMPARE(settings1.value("geometry").toInt(), 777);
1036 QCOMPARE(settings2.value("geometry").toInt(), 5);
1037 QCOMPARE(settings2.value("alpha/geometry").toInt(), 66);
1038 QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777);
1039 QCOMPARE(settings3.value("geometry").toInt(), 66);
1040 QCOMPARE(settings3.value("beta/geometry").toInt(), 777);
1041
1042 settings3.beginGroup(prefix: "gamma");
1043 settings3.setValue(key: "geometry", value: 8888);
1044 QCOMPARE(settings3.value("geometry").toInt(), 8888);
1045 QCOMPARE(settings2.value("geometry").toInt(), 5);
1046 QCOMPARE(settings2.value("alpha/geometry").toInt(), 66);
1047 QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777);
1048 QCOMPARE(settings2.value("alpha/gamma/geometry").toInt(), 8888);
1049 QCOMPARE(settings1.value("geometry").toInt(), 777);
1050
1051 // endGroup() should do nothing if group() is empty
1052 for (int i = 0; i < 10; ++i) {
1053 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::endGroup: No matching beginGroup()");
1054 settings2.endGroup();
1055 }
1056 QCOMPARE(settings2.value("geometry").toInt(), 5);
1057 QCOMPARE(settings2.value("alpha/geometry").toInt(), 66);
1058 QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), 777);
1059 QCOMPARE(settings2.value("alpha/gamma/geometry").toInt(), 8888);
1060
1061 QCOMPARE(settings1.group(), QString("alpha/beta"));
1062 settings1.endGroup();
1063 QCOMPARE(settings1.group(), QString("alpha"));
1064 settings1.endGroup();
1065 QCOMPARE(settings1.group(), QString());
1066 QCOMPARE(settings1.value("geometry").toInt(), 5);
1067 QCOMPARE(settings1.value("alpha/geometry").toInt(), 66);
1068 QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), 777);
1069 QCOMPARE(settings1.value("alpha/gamma/geometry").toInt(), 8888);
1070
1071 settings1.beginGroup(prefix: "delta");
1072 QCOMPARE(settings1.group(), QString("delta"));
1073 settings1.beginGroup(prefix: "");
1074 QCOMPARE(settings1.group(), QString("delta"));
1075 settings1.beginGroup(prefix: "/");
1076 QCOMPARE(settings1.group(), QString("delta"));
1077 settings1.beginGroup(prefix: "////");
1078 QCOMPARE(settings1.group(), QString("delta"));
1079 settings1.beginGroup(prefix: "////omega///epsilon zeta eta theta/ / /");
1080 QCOMPARE(settings1.group(), QString("delta/omega/epsilon zeta eta theta/ / "));
1081 settings1.endGroup();
1082 QCOMPARE(settings1.group(), QString("delta"));
1083 settings1.endGroup();
1084 QCOMPARE(settings1.group(), QString("delta"));
1085 settings1.endGroup();
1086 QCOMPARE(settings1.group(), QString("delta"));
1087 settings1.endGroup();
1088 QCOMPARE(settings1.group(), QString("delta"));
1089 settings1.endGroup();
1090 QCOMPARE(settings1.group(), QString());
1091}
1092
1093/*
1094 Tests setValue() and getXxx().
1095*/
1096void tst_QSettings::setValue()
1097{
1098 QSettings settings(QSettings::UserScope, "software.org", "KillerAPP");
1099
1100 settings.setValue(key: "key 2", value: (int)0x7fffffff);
1101 QCOMPARE(settings.value("key 2").toInt(), (int)0x7fffffff);
1102 QCOMPARE(settings.value("key 2").toString(), QString::number((int)0x7fffffff));
1103 settings.setValue(key: "key 2", value: -1);
1104 QCOMPARE(settings.value("key 2").toInt(), -1);
1105 QCOMPARE(settings.value("key 2").toString(), QString("-1"));
1106 settings.setValue(key: "key 2", value: (int)0x80000000);
1107 QCOMPARE(settings.value("key 2").toInt(), (int)0x80000000);
1108 settings.setValue(key: "key 2", value: (int)0);
1109 QCOMPARE(settings.value("key 2", 123).toInt(), (int)0);
1110 settings.setValue(key: "key 2", value: (int)12345);
1111 QCOMPARE(settings.value("key 2").toInt(), (int)12345);
1112 QCOMPARE(settings.value("no such key", 1234).toInt(), (int)1234);
1113 QCOMPARE(settings.value("no such key").toInt(), (int)0);
1114
1115 settings.setValue(key: "key 2", value: true);
1116 QCOMPARE(settings.value("key 2").toBool(), true);
1117 settings.setValue(key: "key 2", value: false);
1118 QCOMPARE(settings.value("key 2", true).toBool(), false);
1119 settings.setValue(key: "key 2", value: (int)1);
1120 QCOMPARE(settings.value("key 2").toBool(), true);
1121 settings.setValue(key: "key 2", value: (int)-1);
1122 QCOMPARE(settings.value("key 2").toBool(), true);
1123 settings.setValue(key: "key 2", value: (int)0);
1124 QCOMPARE(settings.value("key 2", true).toBool(), false);
1125 settings.setValue(key: "key 2", value: QString("true"));
1126 QCOMPARE(settings.value("key 2").toBool(), true);
1127 settings.setValue(key: "key 2", value: QString("false"));
1128 QCOMPARE(settings.value("key 2", true).toBool(), false);
1129
1130 // The following block should not compile.
1131/*
1132 settings.setValue("key 2", "true");
1133 QCOMPARE(settings.value("key 2").toBool(), true);
1134 settings.setValue("key 2", "false");
1135 QCOMPARE(settings.value("key 2", true).toBool(), false);
1136 settings.setValue("key 2", "");
1137 QCOMPARE(settings.value("key 2", true).toBool(), true);
1138 settings.setValue("key 2", "");
1139 QCOMPARE(settings.value("key 2", false).toBool(), false);
1140 settings.setValue("key 2", "0.000e-00"); // cannot convert double to a bool
1141 QCOMPARE(settings.value("key 2", true).toBool(), true);
1142 settings.setValue("key 2", "0.000e-00");
1143 QCOMPARE(settings.value("key 2", false).toBool(), false);
1144*/
1145
1146 settings.setValue(key: "key 2", value: QStringList());
1147 QCOMPARE(settings.value("key 2").toStringList(), QStringList());
1148 settings.setValue(key: "key 2", value: QStringList(""));
1149 QCOMPARE(settings.value("key 2").toStringList(), QStringList(""));
1150 settings.setValue(key: "key 2", value: QStringList() << "" << "");
1151 QCOMPARE(settings.value("key 2").toStringList(), QStringList() << "" << "");
1152 settings.setValue(key: "key 2", value: QStringList() << "" << "a" << "" << "bc" << "");
1153 QCOMPARE(settings.value("key 2").toStringList(), QStringList() << "" << "a" << "" << "bc" << "");
1154
1155 settings.setValue(key: "key 3", value: QList<QVariant>());
1156 QVERIFY(settings.value("key 3").toList().isEmpty());
1157 settings.setValue(key: "key 3", value: QList<QVariant>() << 1 << QString("a"));
1158 QCOMPARE(settings.value("key 3").toList(), QList<QVariant>() << 1 << QString("a"));
1159
1160 QList<QVariant> outerList;
1161 outerList << 1 << QString("b");
1162 QList<QVariant> innerList = outerList;
1163 outerList.append(t: QVariant(innerList));
1164 outerList.append(t: QVariant(innerList));
1165 outerList << 2 << QString("c");
1166 innerList = outerList;
1167 outerList.append(t: QVariant(innerList));
1168 // outerList: [1, "b", [1, "b"], [1, "b"], 2, "c", [1, "b", [1, "b"], [1, "b"], 2, "c"]]
1169
1170 settings.setValue(key: "key 3", value: outerList);
1171 QCOMPARE(settings.value("key 3").toList(), outerList);
1172 QCOMPARE(settings.value("key 3").toList().size(), 7);
1173
1174 QMap<QString, QVariant> map;
1175 map.insert(key: "1", value: "one");
1176 map.insert(key: "2", value: "two");
1177 map.insert(key: "3", value: outerList);
1178 map.insert(key: "5", value: "cinco");
1179 map.insert(key: "10", value: "zehn");
1180 settings.setValue(key: "key 4", value: map);
1181 QCOMPARE(settings.value("key 4").toMap(), map);
1182}
1183
1184#ifdef QT_BUILD_INTERNAL
1185
1186template<int MetaTypeId>
1187static void testMetaTypesHelper(QSettings::Format format)
1188{
1189 typedef typename MetaEnumToType<MetaTypeId>::Type Type;
1190 const char *key = QMetaType::typeName(type: MetaTypeId);
1191 Type *value = TestValueFactory<MetaTypeId>::create();
1192 QVariant inputVariant = QVariant::fromValue(*value);
1193
1194 static const QSettings::Scope scope = QSettings::UserScope;
1195 static const QString organization("example.org");
1196 static const QString applicationName("FooApp");
1197
1198 {
1199 QSettings settings(format, scope, organization, applicationName);
1200 settings.setValue(key, value: inputVariant);
1201 }
1202
1203 QConfFile::clearCache();
1204
1205 {
1206 QSettings settings(format, scope, organization, applicationName);
1207 QVariant outputVariant = settings.value(key);
1208 if (MetaTypeId != QMetaType::QVariant)
1209 QVERIFY(outputVariant.canConvert(MetaTypeId));
1210 if (outputVariant.type() != inputVariant.type())
1211 qWarning() << "type mismatch between" << inputVariant << "and" << outputVariant;
1212 QCOMPARE(qvariant_cast<Type >(outputVariant), *value);
1213 }
1214
1215 delete value;
1216}
1217
1218#define FOR_EACH_NONSUPPORTED_METATYPE(F)\
1219 F(Void) \
1220 F(Nullptr) \
1221 F(QObjectStar) \
1222 F(QModelIndex) \
1223 F(QJsonObject) \
1224 F(QJsonValue) \
1225 F(QJsonArray) \
1226 F(QJsonDocument) \
1227 F(QPersistentModelIndex) \
1228 F(QCborSimpleType) \
1229 F(QCborValue) \
1230 F(QCborArray) \
1231 F(QCborMap) \
1232
1233#define EXCLUDE_NON_SUPPORTED_METATYPES(MetaTypeName) \
1234template<> void testMetaTypesHelper<QMetaType::MetaTypeName>(QSettings::Format) \
1235{ \
1236 QSKIP("This metatype is not supported by QSettings."); \
1237}
1238FOR_EACH_NONSUPPORTED_METATYPE(EXCLUDE_NON_SUPPORTED_METATYPES)
1239#undef EXCLUDE_NON_SUPPORTED_METATYPES
1240
1241void tst_QSettings::testMetaTypes_data()
1242{
1243 QTest::addColumn<QSettings::Format>(name: "format");
1244 QTest::addColumn<int>(name: "type");
1245
1246#define ADD_METATYPE_TEST_ROW(MetaTypeName, MetaTypeId, RealType) \
1247 { \
1248 const char *formatName = QMetaEnum::fromType<QSettings::Format>().valueToKey(formats[i]); \
1249 const char *typeName = QMetaType::typeName(QMetaType::MetaTypeName); \
1250 QTest::newRow(QString("%1:%2").arg(formatName).arg(typeName).toLatin1().constData()) \
1251 << QSettings::Format(formats[i]) << int(QMetaType::MetaTypeName); \
1252 }
1253 int formats[] = { QSettings::NativeFormat, QSettings::IniFormat };
1254 for (int i = 0; i < int(sizeof(formats) / sizeof(int)); ++i) {
1255 FOR_EACH_CORE_METATYPE(ADD_METATYPE_TEST_ROW)
1256 }
1257#undef ADD_METATYPE_TEST_ROW
1258}
1259
1260typedef void (*TypeTestFunction)(QSettings::Format);
1261
1262void tst_QSettings::testMetaTypes()
1263{
1264 struct TypeTestFunctionGetter
1265 {
1266 static TypeTestFunction get(int type)
1267 {
1268 switch (type) {
1269#define RETURN_CREATE_FUNCTION(MetaTypeName, MetaTypeId, RealType) \
1270 case QMetaType::MetaTypeName: \
1271 return testMetaTypesHelper<QMetaType::MetaTypeName>;
1272FOR_EACH_CORE_METATYPE(RETURN_CREATE_FUNCTION)
1273#undef RETURN_CREATE_FUNCTION
1274 }
1275 return 0;
1276 }
1277 };
1278
1279 QFETCH(QSettings::Format, format);
1280 QFETCH(int, type);
1281
1282 TypeTestFunctionGetter::get(type)(format);
1283}
1284
1285void tst_QSettings::testVariantTypes_data()
1286{
1287 populateWithFormats();
1288}
1289#endif
1290
1291#ifdef QT_BUILD_INTERNAL
1292void tst_QSettings::testVariantTypes()
1293{
1294#define testVal(key, val, tp, rtype) \
1295 { \
1296 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP"); \
1297 settings1.setValue(key, QVariant::fromValue(val)); \
1298 } \
1299 QConfFile::clearCache(); \
1300 { \
1301 QSettings settings2(format, QSettings::UserScope, "software.org", "KillerAPP"); \
1302 QVariant v = settings2.value(key); \
1303 QVERIFY(qvariant_cast<tp >(v) == val); \
1304 QVERIFY(v.type() == QVariant::rtype); \
1305 }
1306
1307 typedef QMap<QString, QVariant> TestVariantMap;
1308
1309 QFETCH(QSettings::Format, format);
1310
1311 TestVariantMap m2;
1312 m2.insert(key: "ene", value: "due");
1313 m2.insert(key: "rike", value: "fake");
1314 m2.insert(key: "borba", value: "dorba");
1315 testVal("key2", m2, TestVariantMap, Map);
1316
1317 QStringList l2;
1318
1319 l2 << "ene" << "due" << "@Point(1 2)" << "@fake";
1320 testVal("key3", l2, QStringList, StringList);
1321
1322 l2.clear();
1323 l2 << "ene" << "due" << "rike" << "fake";
1324 testVal("key3", l2, QStringList, StringList);
1325
1326 QList<QVariant> l3;
1327 QDate date = QDate::currentDate();
1328 QTime time = QTime::currentTime();
1329 l3 << QString("ene") << 10 << QVariant::fromValue(value: QColor(1, 2, 3)) << QVariant(QRect(1, 2, 3, 4))
1330 << QVariant(QSize(4, 56)) << QVariant(QPoint(4, 2)) << true << false << date << time;
1331 testVal("key3", l3, QVariantList, List);
1332
1333 testVal("key4", QString("hello"), QString, String);
1334 testVal("key5", QColor(1, 2, 3), QColor, Color);
1335 testVal("key6", QRect(1, 2, 3, 4), QRect, Rect);
1336 testVal("key7", QSize(4, 56), QSize, Size);
1337 testVal("key8", QPoint(4, 2), QPoint, Point);
1338 testVal("key10", date, QDate, Date);
1339 testVal("key11", time, QTime, Time);
1340 testVal("key12", QByteArray("foo bar"), QByteArray, ByteArray);
1341
1342 {
1343 QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP");
1344 QVERIFY(!settings.contains("key99"));
1345 QCOMPARE(settings.value("key99"), QVariant());
1346
1347 settings.setValue(key: "key99", value: QVariant());
1348 QVERIFY(settings.contains("key99"));
1349 QCOMPARE(settings.value("key99"), QVariant());
1350
1351 settings.setValue(key: "key99", value: QVariant(1));
1352 QVERIFY(settings.contains("key99"));
1353 QCOMPARE(settings.value("key99"), QVariant(1));
1354
1355 settings.setValue(key: "key99", value: QVariant());
1356 QVERIFY(settings.contains("key99"));
1357 QCOMPARE(settings.value("key99"), QVariant());
1358
1359 settings.remove(key: "key99");
1360 QVERIFY(!settings.contains("key99"));
1361 QCOMPARE(settings.value("key99"), QVariant());
1362 }
1363
1364 QList<QVariant> l4;
1365 l4 << QVariant(m2) << QVariant(l2) << QVariant(l3);
1366 testVal("key13", l4, QVariantList, List);
1367 QDateTime dt = QDateTime::currentDateTime();
1368 dt.setOffsetFromUtc(3600);
1369 testVal("key14", dt, QDateTime, DateTime);
1370
1371 // We store key sequences as strings instead of binary variant blob, for improved
1372 // readability in the resulting format.
1373 if (format >= QSettings::InvalidFormat) {
1374 testVal("keysequence", QKeySequence(Qt::ControlModifier + Qt::Key_F1), QKeySequence, KeySequence);
1375 } else {
1376 testVal("keysequence",
1377 QKeySequence(Qt::ControlModifier + Qt::Key_F1).toString(QKeySequence::NativeText),
1378 QString, String);
1379 }
1380
1381#undef testVal
1382}
1383#endif
1384
1385void tst_QSettings::remove()
1386{
1387 QSettings settings0(QSettings::UserScope, "software.org", "KillerAPP");
1388 int initialNumKeys = settings0.allKeys().size();
1389 QCOMPARE(settings0.value("key 1", "123").toString(), QLatin1String("123"));
1390 settings0.remove(key: "key 1");
1391 QCOMPARE(settings0.value("key 1", "456").toString(), QLatin1String("456"));
1392
1393 settings0.setValue(key: "key 1", value: "bubloo");
1394 QCOMPARE(settings0.value("key 1").toString(), QLatin1String("bubloo"));
1395 settings0.remove(key: "key 2");
1396 QCOMPARE(settings0.value("key 1").toString(), QLatin1String("bubloo"));
1397 settings0.remove(key: "key 1");
1398 QCOMPARE(settings0.value("key 1", "789").toString(), QLatin1String("789"));
1399
1400 /*
1401 Make sure that removing a key removes all the subkeys.
1402 */
1403 settings0.setValue(key: "alpha/beta/geometry", value: -7);
1404 settings0.setValue(key: "alpha/beta/geometry/x", value: 1);
1405 settings0.setValue(key: "alpha/beta/geometry/y", value: 2);
1406 settings0.setValue(key: "alpha/beta/geometry/width", value: 3);
1407 settings0.setValue(key: "alpha/beta/geometry/height", value: 4);
1408 settings0.setValue(key: "alpha/gamma/splitter", value: 5);
1409
1410 settings0.remove(key: "alpha/beta/geometry/x");
1411 QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7);
1412 QCOMPARE(settings0.value("alpha/beta/geometry/x", 999).toInt(), 999);
1413 QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2);
1414 QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3);
1415 QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4);
1416 QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5);
1417
1418 settings0.remove(key: "alpha/beta/geometry");
1419 QCOMPARE(settings0.value("alpha/beta/geometry", 777).toInt(), 777);
1420 QCOMPARE(settings0.value("alpha/beta/geometry/x", 111).toInt(), 111);
1421 QCOMPARE(settings0.value("alpha/beta/geometry/y", 222).toInt(), 222);
1422 QCOMPARE(settings0.value("alpha/beta/geometry/width", 333).toInt(), 333);
1423 QCOMPARE(settings0.value("alpha/beta/geometry/height", 444).toInt(), 444);
1424 QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5);
1425
1426 settings0.setValue(key: "alpha/beta/geometry", value: -7);
1427 settings0.setValue(key: "alpha/beta/geometry/x", value: 1);
1428 settings0.setValue(key: "alpha/beta/geometry/y", value: 2);
1429 settings0.setValue(key: "alpha/beta/geometry/width", value: 3);
1430 settings0.setValue(key: "alpha/beta/geometry/height", value: 4);
1431 settings0.setValue(key: "alpha/gamma/splitter", value: 5);
1432 QCOMPARE(settings0.allKeys().size(), initialNumKeys + 6);
1433
1434 settings0.beginGroup(prefix: "alpha/beta/geometry");
1435 settings0.remove(key: "");
1436 settings0.endGroup();
1437 QVERIFY(!settings0.contains("alpha/beta/geometry"));
1438 QVERIFY(!settings0.contains("alpha/beta/geometry/x"));
1439 QVERIFY(!settings0.contains("alpha/beta/geometry/y"));
1440 QVERIFY(!settings0.contains("alpha/beta/geometry/width"));
1441 QVERIFY(!settings0.contains("alpha/beta/geometry/height"));
1442 QVERIFY(settings0.contains("alpha/gamma/splitter"));
1443 QCOMPARE(settings0.allKeys().size(), initialNumKeys + 1);
1444
1445 settings0.beginGroup(prefix: "alpha/beta");
1446 settings0.remove(key: "");
1447 settings0.endGroup();
1448 QVERIFY(!settings0.contains("alpha/beta/geometry"));
1449 QVERIFY(!settings0.contains("alpha/beta/geometry/x"));
1450 QVERIFY(!settings0.contains("alpha/beta/geometry/y"));
1451 QVERIFY(!settings0.contains("alpha/beta/geometry/width"));
1452 QVERIFY(!settings0.contains("alpha/beta/geometry/height"));
1453 QVERIFY(settings0.contains("alpha/gamma/splitter"));
1454 QCOMPARE(settings0.allKeys().size(), initialNumKeys + 1);
1455
1456 settings0.remove(key: "");
1457 QVERIFY(!settings0.contains("alpha/gamma/splitter"));
1458 QCOMPARE(settings0.allKeys().size(), initialNumKeys);
1459
1460 /*
1461 Do it again, but this time let's use setGroup().
1462 */
1463
1464 settings0.setValue(key: "alpha/beta/geometry", value: -7);
1465 settings0.setValue(key: "alpha/beta/geometry/x", value: 1);
1466 settings0.setValue(key: "alpha/beta/geometry/y", value: 2);
1467 settings0.setValue(key: "alpha/beta/geometry/width", value: 3);
1468 settings0.setValue(key: "alpha/beta/geometry/height", value: 4);
1469 settings0.setValue(key: "alpha/gamma/splitter", value: 5);
1470
1471 settings0.beginGroup(prefix: "foo/bar/baz/doesn't");
1472 settings0.remove(key: "exist");
1473 settings0.endGroup();
1474 QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7);
1475 QCOMPARE(settings0.value("alpha/beta/geometry/x").toInt(), 1);
1476 QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2);
1477 QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3);
1478 QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4);
1479 QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5);
1480
1481 settings0.beginGroup(prefix: "alpha/beta/geometry");
1482 settings0.remove(key: "x");
1483 settings0.endGroup();
1484 QCOMPARE(settings0.value("alpha/beta/geometry").toInt(), -7);
1485 QCOMPARE(settings0.value("alpha/beta/geometry/x", 999).toInt(), 999);
1486 QCOMPARE(settings0.value("alpha/beta/geometry/y").toInt(), 2);
1487 QCOMPARE(settings0.value("alpha/beta/geometry/width").toInt(), 3);
1488 QCOMPARE(settings0.value("alpha/beta/geometry/height").toInt(), 4);
1489 QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5);
1490
1491 settings0.remove(key: "alpha/beta");
1492 QCOMPARE(settings0.value("alpha/beta/geometry", 777).toInt(), 777);
1493 QCOMPARE(settings0.value("alpha/beta/geometry/x", 111).toInt(), 111);
1494 QCOMPARE(settings0.value("alpha/beta/geometry/y", 222).toInt(), 222);
1495 QCOMPARE(settings0.value("alpha/beta/geometry/width", 333).toInt(), 333);
1496 QCOMPARE(settings0.value("alpha/beta/geometry/height", 444).toInt(), 444);
1497 QCOMPARE(settings0.value("alpha/gamma/splitter").toInt(), 5);
1498
1499 settings0.clear();
1500 QCOMPARE(settings0.value("alpha/gamma/splitter", 888).toInt(), 888);
1501
1502 /*
1503 OK, now let's check what happens if settings are spread across
1504 multiple files (user vs. global, product-specific vs.
1505 company-wide).
1506 */
1507
1508 QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP");
1509 QSettings settings2(QSettings::UserScope, "software.org");
1510
1511 QScopedPointer<QSettings> settings3;
1512 QScopedPointer<QSettings> settings4;
1513
1514 if (m_canWriteNativeSystemSettings) {
1515 settings3.reset(other: new QSettings(QSettings::SystemScope, "software.org", "KillerAPP"));
1516 settings4.reset(other: new QSettings(QSettings::SystemScope, "software.org"));
1517 settings3->setValue(key: "key 1", value: "blah");
1518 settings4->setValue(key: "key 1", value: "doodah");
1519 }
1520
1521 settings2.setValue(key: "key 1", value: "whoa");
1522 settings1.setValue(key: "key 1", value: "gurgle");
1523 QCOMPARE(settings1.value("key 1").toString(), QString("gurgle"));
1524 QCOMPARE(settings2.value("key 1").toString(), QString("whoa"));
1525
1526 if (m_canWriteNativeSystemSettings) {
1527 QCOMPARE(settings3->value("key 1").toString(), QString("blah"));
1528 QCOMPARE(settings4->value("key 1").toString(), QString("doodah"));
1529 }
1530
1531 settings1.remove(key: "key 1");
1532 QCOMPARE(settings1.value("key 1").toString(), QString("whoa"));
1533 QCOMPARE(settings2.value("key 1").toString(), QString("whoa"));
1534 if (m_canWriteNativeSystemSettings) {
1535 QCOMPARE(settings3->value("key 1").toString(), QString("blah"));
1536 QCOMPARE(settings4->value("key 1").toString(), QString("doodah"));
1537 }
1538
1539 if (m_canWriteNativeSystemSettings) {
1540 settings2.remove(key: "key 1");
1541 QCOMPARE(settings1.value("key 1").toString(), QString("blah"));
1542 QCOMPARE(settings2.value("key 1").toString(), QString("doodah"));
1543 QCOMPARE(settings3->value("key 1").toString(), QString("blah"));
1544 QCOMPARE(settings4->value("key 1").toString(), QString("doodah"));
1545
1546 settings3->remove(key: "key 1");
1547 QCOMPARE(settings1.value("key 1").toString(), QString("doodah"));
1548 QCOMPARE(settings2.value("key 1").toString(), QString("doodah"));
1549 QCOMPARE(settings3->value("key 1").toString(), QString("doodah"));
1550 QCOMPARE(settings4->value("key 1").toString(), QString("doodah"));
1551
1552 settings4->remove(key: "key 1");
1553 QVERIFY(!settings1.contains("key 1"));
1554 QVERIFY(!settings2.contains("key 1"));
1555 QVERIFY(!settings3->contains("key 1"));
1556 QVERIFY(!settings4->contains("key 1"));
1557 }
1558
1559 /*
1560 Get ready for the next part of the test.
1561 */
1562
1563 settings1.clear();
1564 settings2.clear();
1565 if (m_canWriteNativeSystemSettings) {
1566 settings3->clear();
1567 settings4->clear();
1568 }
1569
1570 settings1.sync();
1571 settings2.sync();
1572
1573 if (m_canWriteNativeSystemSettings) {
1574 settings3->sync();
1575 settings4->sync();
1576 }
1577
1578 /*
1579 Check that recursive removes work correctly when some of the
1580 keys are loaded from the file and others have been modified in
1581 memory (corresponds to originalKeys vs. addedKeys in the
1582 QSettingsFile code).
1583 */
1584
1585 settings1.setValue(key: "alpha/beta/geometry", value: -7);
1586 settings1.setValue(key: "alpha/beta/geometry/x", value: 1);
1587 settings1.setValue(key: "alpha/beta/geometry/y", value: 2);
1588 settings1.setValue(key: "alpha/gamma/splitter", value: 5);
1589 settings1.sync();
1590
1591 settings1.setValue(key: "alpha/beta/geometry/width", value: 3);
1592 settings1.setValue(key: "alpha/beta/geometry/height", value: 4);
1593
1594 settings1.remove(key: "alpha/beta/geometry/y");
1595 QVERIFY(settings1.contains("alpha/beta/geometry"));
1596 QVERIFY(settings1.contains("alpha/beta/geometry/x"));
1597 QVERIFY(!settings1.contains("alpha/beta/geometry/y"));
1598 QVERIFY(settings1.contains("alpha/beta/geometry/width"));
1599 QVERIFY(settings1.contains("alpha/beta/geometry/height"));
1600 QCOMPARE(settings1.allKeys().size(), initialNumKeys + 5);
1601
1602 settings1.remove(key: "alpha/beta/geometry/y");
1603 QCOMPARE(settings1.allKeys().size(), initialNumKeys + 5);
1604
1605 settings1.remove(key: "alpha/beta/geometry/height");
1606 QVERIFY(settings1.contains("alpha/beta/geometry"));
1607 QVERIFY(settings1.contains("alpha/beta/geometry/x"));
1608 QVERIFY(!settings1.contains("alpha/beta/geometry/y"));
1609 QVERIFY(settings1.contains("alpha/beta/geometry/width"));
1610 QVERIFY(!settings1.contains("alpha/beta/geometry/height"));
1611 QCOMPARE(settings1.allKeys().size(), initialNumKeys + 4);
1612
1613 settings1.remove(key: "alpha/beta/geometry");
1614 QVERIFY(!settings1.contains("alpha/beta/geometry"));
1615 QVERIFY(!settings1.contains("alpha/beta/geometry/x"));
1616 QVERIFY(!settings1.contains("alpha/beta/geometry/y"));
1617 QVERIFY(!settings1.contains("alpha/beta/geometry/width"));
1618 QVERIFY(!settings1.contains("alpha/beta/geometry/height"));
1619 QVERIFY(settings1.contains("alpha/gamma/splitter"));
1620 QCOMPARE(settings1.allKeys().size(), initialNumKeys + 1);
1621
1622 settings1.sync();
1623 QVERIFY(!settings1.contains("alpha/beta/geometry"));
1624 QVERIFY(!settings1.contains("alpha/beta/geometry/x"));
1625 QVERIFY(!settings1.contains("alpha/beta/geometry/y"));
1626 QVERIFY(!settings1.contains("alpha/beta/geometry/width"));
1627 QVERIFY(!settings1.contains("alpha/beta/geometry/height"));
1628 QVERIFY(settings1.contains("alpha/gamma/splitter"));
1629 QCOMPARE(settings1.allKeys().size(), initialNumKeys + 1);
1630}
1631
1632/*
1633 Tests contains() and keys().
1634*/
1635void tst_QSettings::contains()
1636{
1637 QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP");
1638 int initialNumKeys = settings1.allKeys().size(); // 0 on all platforms but OS X.
1639 settings1.setValue(key: "alpha/beta/geometry", value: -7);
1640 settings1.setValue(key: "alpha/beta/geometry/x", value: 1);
1641 settings1.setValue(key: "alpha/beta/geometry/y", value: 2);
1642 settings1.setValue(key: "alpha/beta/geometry/width", value: 3);
1643 settings1.setValue(key: "alpha/beta/geometry/height", value: 4);
1644 settings1.setValue(key: "alpha/gamma/splitter", value: 5);
1645 settings1.setValue(key: "alpha/gamma/splitter/ /", value: 5);
1646
1647 QVERIFY(!settings1.contains("alpha"));
1648 QVERIFY(!settings1.contains("alpha/beta"));
1649 QVERIFY(!settings1.contains("///alpha///beta///"));
1650 QVERIFY(settings1.contains("alpha/beta/geometry"));
1651 QVERIFY(settings1.contains("///alpha///beta//geometry//"));
1652 QVERIFY(settings1.contains("alpha/beta/geometry/x"));
1653 QVERIFY(settings1.contains("alpha/beta/geometry/y"));
1654 QVERIFY(settings1.contains("alpha/beta/geometry/width"));
1655 QVERIFY(settings1.contains("alpha/beta/geometry/height"));
1656 QVERIFY(!settings1.contains("alpha/beta/geometry/height/foo/bar/doesn't/exist"));
1657 QVERIFY(!settings1.contains("alpha/gamma"));
1658 QVERIFY(settings1.contains("alpha/gamma/splitter"));
1659 QVERIFY(settings1.contains("alpha/gamma/splitter/ "));
1660 QVERIFY(settings1.contains("////alpha/gamma/splitter// ////"));
1661
1662 settings1.beginGroup(prefix: "alpha");
1663 QVERIFY(!settings1.contains("beta"));
1664 QVERIFY(!settings1.contains("/////beta///"));
1665 QVERIFY(settings1.contains("beta/geometry"));
1666 QVERIFY(settings1.contains("/////beta//geometry//"));
1667 QVERIFY(settings1.contains("beta/geometry/x"));
1668 QVERIFY(settings1.contains("beta/geometry/y"));
1669 QVERIFY(settings1.contains("beta/geometry/width"));
1670 QVERIFY(settings1.contains("beta/geometry/height"));
1671 QVERIFY(!settings1.contains("beta/geometry/height/foo/bar/doesn't/exist"));
1672 QVERIFY(!settings1.contains("gamma"));
1673 QVERIFY(settings1.contains("gamma/splitter"));
1674 QVERIFY(settings1.contains("gamma/splitter/ "));
1675 QVERIFY(settings1.contains("////gamma/splitter// ////"));
1676
1677 settings1.beginGroup(prefix: "beta/geometry");
1678 QVERIFY(settings1.contains("x"));
1679 QVERIFY(settings1.contains("y"));
1680 QVERIFY(settings1.contains("width"));
1681 QVERIFY(settings1.contains("height"));
1682 QVERIFY(!settings1.contains("height/foo/bar/doesn't/exist"));
1683
1684 QStringList keys = settings1.allKeys();
1685 QStringList expectedResult = QStringList() << "x" << "y" << "width" << "height";
1686 keys.sort();
1687 expectedResult.sort();
1688 int i;
1689 QCOMPARE(keys, expectedResult);
1690 for (i = 0; i < keys.size(); ++i) {
1691 QVERIFY(settings1.contains(keys.at(i)));
1692 }
1693
1694 settings1.endGroup();
1695 QCOMPARE(settings1.group(), QLatin1String("alpha"));
1696 keys = settings1.allKeys();
1697 QCOMPARE(keys.size(), expectedResult.size() + 3);
1698 for (i = 0; i < keys.size(); ++i) {
1699 QVERIFY(settings1.contains(keys.at(i)));
1700 }
1701
1702 settings1.endGroup();
1703 QVERIFY(settings1.group().isEmpty());
1704 keys = settings1.allKeys();
1705
1706 QCOMPARE(keys.size(), initialNumKeys + 7);
1707 for (i = 0; i < keys.size(); ++i) {
1708 QVERIFY(settings1.contains(keys.at(i)));
1709 }
1710}
1711
1712void tst_QSettings::sync()
1713{
1714 /*
1715 What we're trying to test here is the case where two
1716 instances of the same application access the same preference
1717 files. We want to make sure that the results are 'merged',
1718 rather than having the last application overwrite settings
1719 set by the first application (like in Qt 3).
1720
1721 This is only applicable to the INI format. The Windows
1722 registry and Mac's CFPreferences API should take care of this
1723 by themselves.
1724 */
1725
1726 QSettings settings1(QSettings::IniFormat, QSettings::UserScope, "software.org");
1727 settings1.setValue(key: "alpha/beta/geometry", value: -7);
1728 settings1.setValue(key: "alpha/beta/geometry/x", value: 1);
1729 settings1.setValue(key: "alpha/beta/geometry/y", value: 2);
1730 settings1.setValue(key: "alpha/beta/geometry/width", value: 3);
1731 settings1.setValue(key: "alpha/beta/geometry/height", value: 4);
1732 settings1.setValue(key: "alpha/gamma/splitter", value: 5);
1733 settings1.sync(); // and it all goes into the file
1734
1735 QSettings settings2(QSettings::IniFormat, QSettings::UserScope, "other.software.org");
1736 settings2.setValue(key: "alpha/beta/geometry/x", value: 8);
1737 settings2.sync();
1738
1739 settings2.setValue(key: "moo/beta/geometry", value: -7);
1740 settings2.setValue(key: "moo/beta/geometry/x", value: 1);
1741 settings2.setValue(key: "moo/beta/geometry/y", value: 2);
1742 settings2.setValue(key: "moo/beta/geometry/width", value: 3);
1743 settings2.setValue(key: "moo/beta/geometry/height", value: 4);
1744 settings2.setValue(key: "moo/gamma/splitter", value: 5);
1745 settings2.setValue(key: "alpha/gamma/splitter", value: 15);
1746 settings2.remove(key: "alpha/beta/geometry/x");
1747 settings2.remove(key: "alpha/beta/geometry/y"); // should do nothing
1748
1749 // Now "some other app" will change other.software.org.ini
1750 QString userConfDir = settingsPath("__user__") + QDir::separator();
1751#if !defined(Q_OS_WINRT)
1752 unlink(name: (userConfDir + "other.software.org.ini").toLatin1());
1753 rename(old: (userConfDir + "software.org.ini").toLatin1(),
1754 new: (userConfDir + "other.software.org.ini").toLatin1());
1755#else
1756 QFile::remove(userConfDir + "other.software.org.ini");
1757 QFile::rename(userConfDir + "software.org.ini" , userConfDir + "other.software.org.ini");
1758#endif
1759
1760 settings2.sync();
1761
1762 // And voila, we should be merged
1763
1764 QCOMPARE(settings2.value("alpha/beta/geometry").toInt(), -7);
1765 QVERIFY(!settings2.contains("alpha/beta/geometry/x")); // <----- removed by settings2
1766 QCOMPARE(settings2.value("alpha/beta/geometry/y").toInt(), 2);
1767 QCOMPARE(settings2.value("alpha/beta/geometry/width").toInt(), 3);
1768 QCOMPARE(settings2.value("alpha/beta/geometry/height").toInt(), 4);
1769 QCOMPARE(settings2.value("alpha/gamma/splitter").toInt(), 15); // <---- set by settings2
1770 QCOMPARE(settings2.value("moo/beta/geometry").toInt(), -7);
1771 QCOMPARE(settings2.value("moo/beta/geometry/x").toInt(), 1);
1772 QCOMPARE(settings2.value("moo/beta/geometry/y").toInt(), 2);
1773 QCOMPARE(settings2.value("moo/beta/geometry/width").toInt(), 3);
1774 QCOMPARE(settings2.value("moo/beta/geometry/height").toInt(), 4);
1775 QCOMPARE(settings2.value("moo/gamma/splitter").toInt(), 5);
1776 QCOMPARE(settings2.allKeys().count(), 11);
1777
1778 // Now, software.org.ini no longer exists, this is same as another app
1779 // clearing all settings.
1780 settings1.sync();
1781 QCOMPARE(settings1.allKeys().count(), 0);
1782
1783 // Now "some other app" will change software.org.ini
1784 QVERIFY(QFile::rename((userConfDir + "other.software.org.ini").toLatin1(),
1785 (userConfDir + "software.org.ini").toLatin1()));
1786
1787 settings1.sync();
1788 QCOMPARE(settings1.value("alpha/beta/geometry").toInt(), -7);
1789 QCOMPARE(settings1.value("alpha/beta/geometry/y").toInt(), 2);
1790 QCOMPARE(settings1.value("alpha/beta/geometry/width").toInt(), 3);
1791 QCOMPARE(settings1.value("alpha/beta/geometry/height").toInt(), 4);
1792 QCOMPARE(settings1.value("alpha/gamma/splitter").toInt(), 15);
1793 QCOMPARE(settings1.value("moo/beta/geometry").toInt(), -7);
1794 QCOMPARE(settings1.value("moo/beta/geometry/x").toInt(), 1);
1795 QCOMPARE(settings1.value("moo/beta/geometry/y").toInt(), 2);
1796 QCOMPARE(settings1.value("moo/beta/geometry/width").toInt(), 3);
1797 QCOMPARE(settings1.value("moo/beta/geometry/height").toInt(), 4);
1798 QCOMPARE(settings1.value("moo/gamma/splitter").toInt(), 5);
1799 QCOMPARE(settings1.allKeys().count(), 11);
1800}
1801
1802void tst_QSettings::syncNonWriteableDir()
1803{
1804 QTemporaryDir tempDir;
1805 QVERIFY2(tempDir.isValid(), qUtf8Printable(tempDir.errorString()));
1806
1807 // first, create a file
1808 QString filename = tempDir.path() + "/config.ini";
1809 {
1810 QFile f(filename);
1811 QVERIFY2(f.open(QIODevice::WriteOnly), qUtf8Printable(f.errorString()));
1812 }
1813
1814 // second, make the dir unwriteable
1815 QVERIFY(QFile::setPermissions(tempDir.path(), QFile::ReadUser | QFile::ExeUser));
1816 struct UndoSetPermissions {
1817 QString name;
1818 UndoSetPermissions(const QString &name) : name(name) {}
1819 ~UndoSetPermissions()
1820 { QFile::setPermissions(filename: name, permissionSpec: QFile::ReadUser | QFile::WriteUser | QFile::ExeUser); }
1821 };
1822 UndoSetPermissions undo(tempDir.path()); // otherwise, QTemporaryDir will fail
1823
1824 {
1825 QSettings settings(filename, QSettings::IniFormat);
1826 QVERIFY(settings.isAtomicSyncRequired());
1827 settings.setAtomicSyncRequired(false);
1828 settings.setValue(key: "alpha/beta", value: 1);
1829 settings.sync();
1830 QCOMPARE(settings.status(), QSettings::NoError);
1831 }
1832
1833 QVERIFY(QFileInfo(filename).size() != 0);
1834 QSettings settings(filename, QSettings::IniFormat);
1835 QCOMPARE(settings.value("alpha/beta"), QVariant(1));
1836}
1837
1838#ifdef Q_OS_WIN
1839void tst_QSettings::syncAlternateDataStream()
1840{
1841 QTemporaryDir tempDir;
1842 QVERIFY2(tempDir.isValid(), qUtf8Printable(tempDir.errorString()));
1843
1844 // first, create a file
1845 QString filename = tempDir.path() + "/file";
1846 {
1847 QFile f(filename);
1848 QVERIFY2(f.open(QIODevice::WriteOnly), qUtf8Printable(f.errorString()));
1849 }
1850
1851 // then create an ADS
1852 filename += ":config.ini";
1853 {
1854 QFile f(filename);
1855 if (!f.open(QIODevice::WriteOnly))
1856 QSKIP("Could not create ADS file (" + f.errorString().toUtf8() + ") - FAT drive?");
1857 }
1858
1859 {
1860 QSettings settings(filename, QSettings::IniFormat);
1861 QVERIFY(settings.isAtomicSyncRequired());
1862 settings.setAtomicSyncRequired(false);
1863 settings.setValue("alpha/beta", 1);
1864 settings.sync();
1865 QCOMPARE(settings.status(), QSettings::NoError);
1866 }
1867
1868 QVERIFY(QFileInfo(filename).size() != 0);
1869 QSettings settings(filename, QSettings::IniFormat);
1870 QCOMPARE(settings.value("alpha/beta"), QVariant(1));
1871}
1872#endif
1873
1874void tst_QSettings::setFallbacksEnabled_data()
1875{
1876 populateWithFormats();
1877}
1878
1879void tst_QSettings::setFallbacksEnabled()
1880{
1881 QFETCH(QSettings::Format, format);
1882
1883 if (!m_canWriteNativeSystemSettings && format == QSettings::NativeFormat)
1884 QSKIP(insufficientPermissionSkipMessage);
1885
1886 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP");
1887 QSettings settings2(format, QSettings::UserScope, "software.org");
1888 QSettings settings3(format, QSettings::SystemScope, "software.org", "KillerAPP");
1889 QSettings settings4(format, QSettings::SystemScope, "software.org");
1890
1891 settings1.setValue(key: "key 1", value: "alpha");
1892 settings2.setValue(key: "key 1", value: "beta");
1893 settings3.setValue(key: "key 1", value: "gamma");
1894 settings4.setValue(key: "key 1", value: "delta");
1895
1896 settings1.setValue(key: "key 2", value: "alpha");
1897 settings2.setValue(key: "key 2", value: "beta");
1898 settings3.setValue(key: "key 2", value: "gamma");
1899
1900 settings1.setValue(key: "key 3", value: "alpha");
1901 settings3.setValue(key: "key 3", value: "gamma");
1902 settings4.setValue(key: "key 3", value: "delta");
1903
1904 settings1.setValue(key: "key 4", value: "alpha");
1905 settings2.setValue(key: "key 4", value: "beta");
1906 settings4.setValue(key: "key 4", value: "delta");
1907
1908 settings2.setValue(key: "key 5", value: "beta");
1909 settings3.setValue(key: "key 5", value: "gamma");
1910 settings4.setValue(key: "key 5", value: "delta");
1911
1912 QVERIFY(settings1.fallbacksEnabled());
1913 QVERIFY(settings2.fallbacksEnabled());
1914 QVERIFY(settings3.fallbacksEnabled());
1915 QVERIFY(settings4.fallbacksEnabled());
1916
1917 settings1.setFallbacksEnabled(false);
1918 settings2.setFallbacksEnabled(false);
1919 settings3.setFallbacksEnabled(false);
1920 settings4.setFallbacksEnabled(false);
1921
1922 QVERIFY(!settings1.fallbacksEnabled());
1923 QVERIFY(!settings2.fallbacksEnabled());
1924 QVERIFY(!settings3.fallbacksEnabled());
1925 QVERIFY(!settings4.fallbacksEnabled());
1926
1927 /*
1928 Make sure that the QSettings objects can still access their
1929 main associated file when fallbacks are turned off.
1930 */
1931
1932 QCOMPARE(settings1.value("key 1").toString(), QString("alpha"));
1933 QCOMPARE(settings2.value("key 1").toString(), QString("beta"));
1934 QCOMPARE(settings3.value("key 1").toString(), QString("gamma"));
1935 QCOMPARE(settings4.value("key 1").toString(), QString("delta"));
1936
1937 QCOMPARE(settings1.value("key 2").toString(), QString("alpha"));
1938 QCOMPARE(settings2.value("key 2").toString(), QString("beta"));
1939 QCOMPARE(settings3.value("key 2").toString(), QString("gamma"));
1940 QVERIFY(!settings4.contains("key 2"));
1941
1942 QCOMPARE(settings1.value("key 3").toString(), QString("alpha"));
1943 QCOMPARE(settings3.value("key 3").toString(), QString("gamma"));
1944 QCOMPARE(settings4.value("key 3").toString(), QString("delta"));
1945 QVERIFY(!settings2.contains("key 3"));
1946
1947 QCOMPARE(settings1.value("key 4").toString(), QString("alpha"));
1948 QCOMPARE(settings2.value("key 4").toString(), QString("beta"));
1949 QCOMPARE(settings4.value("key 4").toString(), QString("delta"));
1950 QVERIFY(!settings3.contains("key 4"));
1951
1952 QCOMPARE(settings2.value("key 5").toString(), QString("beta"));
1953 QCOMPARE(settings3.value("key 5").toString(), QString("gamma"));
1954 QCOMPARE(settings4.value("key 5").toString(), QString("delta"));
1955 QVERIFY(!settings1.contains("key 5"));
1956
1957 QCOMPARE(settings1.value("key 1").toString(), QString("alpha"));
1958 QCOMPARE(settings1.value("key 5").toString(), QString(""));
1959 QVERIFY(settings1.contains("key 1"));
1960 QVERIFY(!settings1.contains("key 5"));
1961}
1962
1963void tst_QSettings::testChildKeysAndGroups_data()
1964{
1965 populateWithFormats();
1966}
1967
1968void tst_QSettings::testChildKeysAndGroups()
1969{
1970 QFETCH(QSettings::Format, format);
1971
1972 QSettings settings1(format, QSettings::UserScope, "software.org");
1973 settings1.setFallbacksEnabled(false);
1974 settings1.setValue(key: "alpha/beta/geometry", value: -7);
1975 settings1.setValue(key: "alpha/beta/geometry/x", value: 1);
1976 settings1.setValue(key: "alpha/beta/geometry/y", value: 2);
1977 settings1.setValue(key: "alpha/beta/geometry/width", value: 3);
1978 settings1.setValue(key: "alpha/beta/geometry/height", value: 4);
1979 settings1.setValue(key: "alpha/gamma/splitter", value: 5);
1980
1981 QCOMPARE(settings1.childKeys(), QStringList());
1982 QCOMPARE(settings1.childGroups(), QStringList() << "alpha");
1983
1984 settings1.beginGroup(prefix: "/alpha");
1985 QCOMPARE(settings1.childKeys(), QStringList());
1986 QStringList children = settings1.childGroups();
1987 children.sort();
1988 QCOMPARE(children, QStringList() << "beta" << "gamma");
1989
1990 settings1.beginGroup(prefix: "/beta");
1991 QCOMPARE(settings1.childKeys(), QStringList() << "geometry");
1992 QCOMPARE(settings1.childGroups(), QStringList() << "geometry");
1993
1994 settings1.beginGroup(prefix: "/geometry");
1995 children = settings1.childKeys();
1996 children.sort();
1997 QCOMPARE(children, QStringList() << "height" << "width" << "x" << "y");
1998 QCOMPARE(settings1.childGroups(), QStringList());
1999
2000 settings1.beginGroup(prefix: "/width");
2001 QCOMPARE(settings1.childKeys(), QStringList());
2002 QCOMPARE(settings1.childGroups(), QStringList());
2003
2004 settings1.endGroup();
2005 settings1.endGroup();
2006 settings1.endGroup();
2007 settings1.endGroup();
2008
2009 {
2010 QSettings settings2("other.software.org");
2011 settings2.setValue(key: "viewbar/foo/test1", value: "1");
2012 settings2.setValue(key: "viewbar/foo/test2", value: "2");
2013 settings2.setValue(key: "viewbar/foo/test3", value: "3");
2014 settings2.setValue(key: "viewbar/foo/test4", value: "4");
2015 settings2.setValue(key: "viewbar/foo/test5", value: "5");
2016 settings2.setValue(key: "viewbar/bar/test1", value: "1");
2017 settings2.setValue(key: "viewbar/bar/test2", value: "2");
2018 settings2.setValue(key: "viewbar/bar/test3", value: "3");
2019 settings2.setValue(key: "viewbar/bar/test4", value: "4");
2020 settings2.setValue(key: "viewbar/bar/test5", value: "5");
2021
2022 settings2.beginGroup(prefix: "viewbar");
2023 QStringList l = settings2.childGroups();
2024 settings2.endGroup();
2025 l.sort();
2026 QCOMPARE(l, QStringList() << "bar" << "foo");
2027 }
2028}
2029
2030void tst_QSettings::testUpdateRequestEvent()
2031{
2032 const QString oldCur = QDir::currentPath();
2033 QString dataLocation = QStandardPaths::writableLocation(type: QStandardPaths::AppLocalDataLocation);
2034 QVERIFY(QDir::root().mkpath(dataLocation));
2035 QDir::setCurrent(dataLocation);
2036
2037 QFile::remove(fileName: "foo");
2038 QVERIFY(!QFile::exists("foo"));
2039
2040 QSettings settings1("foo", QSettings::IniFormat);
2041 QVERIFY(!QFile::exists("foo"));
2042 QCOMPARE(QFileInfo("foo").size(), qint64(0));
2043 settings1.setValue(key: "key1", value: 1);
2044 QCOMPARE(QFileInfo("foo").size(), qint64(0));
2045
2046 QTRY_VERIFY(QFileInfo("foo").size() > 0);
2047
2048 settings1.remove(key: "key1");
2049 QVERIFY(QFileInfo("foo").size() > 0);
2050
2051 QTRY_COMPARE(QFileInfo("foo").size(), qint64(0));
2052
2053 settings1.setValue(key: "key2", value: 2);
2054 QCOMPARE(QFileInfo("foo").size(), qint64(0));
2055
2056 QTRY_VERIFY(QFileInfo("foo").size() > 0);
2057
2058 settings1.clear();
2059 QVERIFY(QFileInfo("foo").size() > 0);
2060
2061 QTRY_COMPARE(QFileInfo("foo").size(), qint64(0));
2062
2063 QDir::setCurrent(oldCur);
2064}
2065
2066const int NumIterations = 5;
2067const int NumThreads = 4;
2068int numThreadSafetyFailures;
2069
2070class SettingsThread : public QThread
2071{
2072public:
2073 void run();
2074 void start(int n) { param = n; QThread::start(); }
2075
2076private:
2077 int param;
2078};
2079
2080void SettingsThread::run()
2081{
2082 for (int i = 0; i < NumIterations; ++i) {
2083 QSettings settings("software.org", "KillerAPP");
2084 settings.setValue(key: QString::number((param * NumIterations) + i), value: param);
2085 settings.sync();
2086 if (settings.status() != QSettings::NoError) {
2087 QWARN(qPrintable(QString("Unexpected QSettings status %1").arg((int)settings.status())));
2088 ++numThreadSafetyFailures;
2089 }
2090 }
2091}
2092
2093void tst_QSettings::testThreadSafety()
2094{
2095 SettingsThread threads[NumThreads];
2096 int i, j;
2097
2098 numThreadSafetyFailures = 0;
2099
2100 for (i = 0; i < NumThreads; ++i)
2101 threads[i].start(n: i + 1);
2102 for (i = 0; i < NumThreads; ++i)
2103 threads[i].wait();
2104
2105 QSettings settings("software.org", "KillerAPP");
2106 for (i = 0; i < NumThreads; ++i) {
2107 int param = i + 1;
2108 for (j = 0; j < NumIterations; ++j) {
2109 QCOMPARE(settings.value(QString::number((param * NumIterations) + j)).toInt(), param);
2110 }
2111 }
2112
2113 QCOMPARE(numThreadSafetyFailures, 0);
2114}
2115
2116#ifdef QT_BUILD_INTERNAL
2117void tst_QSettings::testNormalizedKey_data()
2118{
2119 QTest::addColumn<QString>(name: "inKey");
2120 QTest::addColumn<QString>(name: "outKey");
2121
2122 QTest::newRow(dataTag: "empty1") << "" << "";
2123 QTest::newRow(dataTag: "empty2") << "/" << "";
2124 QTest::newRow(dataTag: "empty3") << "//" << "";
2125 QTest::newRow(dataTag: "empty4") << "///" << "";
2126
2127 QTest::newRow(dataTag: "a1") << "a" << "a";
2128 QTest::newRow(dataTag: "a2") << "/a" << "a";
2129 QTest::newRow(dataTag: "a3") << "a/" << "a";
2130 QTest::newRow(dataTag: "a4") << "//a" << "a";
2131 QTest::newRow(dataTag: "a5") << "a//" << "a";
2132 QTest::newRow(dataTag: "a6") << "///a" << "a";
2133 QTest::newRow(dataTag: "a7") << "a///" << "a";
2134 QTest::newRow(dataTag: "a8") << "///a/" << "a";
2135 QTest::newRow(dataTag: "a9") << "/a///" << "a";
2136
2137 QTest::newRow(dataTag: "ab1") << "aaa/bbb" << "aaa/bbb";
2138 QTest::newRow(dataTag: "ab2") << "/aaa/bbb" << "aaa/bbb";
2139 QTest::newRow(dataTag: "ab3") << "aaa/bbb/" << "aaa/bbb";
2140 QTest::newRow(dataTag: "ab4") << "/aaa/bbb/" << "aaa/bbb";
2141 QTest::newRow(dataTag: "ab5") << "aaa///bbb" << "aaa/bbb";
2142 QTest::newRow(dataTag: "ab6") << "aaa///bbb/" << "aaa/bbb";
2143 QTest::newRow(dataTag: "ab7") << "/aaa///bbb/" << "aaa/bbb";
2144 QTest::newRow(dataTag: "ab8") << "////aaa///bbb////" << "aaa/bbb";
2145}
2146#endif
2147
2148#ifdef QT_BUILD_INTERNAL
2149void tst_QSettings::testNormalizedKey()
2150{
2151 QFETCH(QString, inKey);
2152 QFETCH(QString, outKey);
2153
2154 inKey.detach();
2155
2156 QString result = QSettingsPrivate::normalizedKey(key: inKey);
2157 QCOMPARE(result, outKey);
2158
2159 /*
2160 If the key is already normalized, we verify that outKey is
2161 just a shallow copy of the input string. This is an important
2162 optimization that shouldn't be removed accidentally.
2163 */
2164 if (inKey == outKey) {
2165 QVERIFY(!result.isDetached());
2166 } else {
2167 if (!result.isEmpty()) {
2168 QVERIFY(result.isDetached());
2169 }
2170 }
2171}
2172#endif
2173
2174void tst_QSettings::testEmptyData()
2175{
2176 QString filename(settingsPath("empty.ini"));
2177 QFile::remove(fileName: filename);
2178 QVERIFY(!QFile::exists(filename));
2179
2180 QString nullString;
2181 QString emptyString("");
2182 QStringList emptyList;
2183 QStringList list;
2184 QStringList list2;
2185
2186 QVariantList emptyVList;
2187 QVariantList vList, vList2, vList3;
2188
2189 list << emptyString << nullString;
2190 list2 << emptyString;
2191 vList << emptyString;
2192 vList2 << emptyString << nullString;
2193 vList3 << QString("foo");
2194
2195 {
2196 QSettings settings(filename, QSettings::IniFormat);
2197 settings.setValue(key: "nullString", value: nullString);
2198 settings.setValue(key: "emptyString", value: emptyString);
2199 settings.setValue(key: "emptyList", value: emptyList);
2200 settings.setValue(key: "list", value: list);
2201 settings.setValue(key: "list2", value: list2);
2202 settings.setValue(key: "emptyVList", value: emptyVList);
2203 settings.setValue(key: "vList", value: vList);
2204 settings.setValue(key: "vList2", value: vList2);
2205 settings.setValue(key: "vList3", value: vList3);
2206 QCOMPARE(settings.status(), QSettings::NoError);
2207 }
2208 {
2209 QSettings settings(filename, QSettings::IniFormat);
2210 QCOMPARE(settings.value("nullString").toString(), nullString);
2211 QCOMPARE(settings.value("emptyString").toString(), emptyString);
2212 QCOMPARE(settings.value("emptyList").toStringList(), emptyList);
2213 QCOMPARE(settings.value("list").toStringList(), list);
2214 QCOMPARE(settings.value("list2").toStringList(), list2);
2215 QCOMPARE(settings.value("emptyVList").toList(), emptyVList);
2216 QCOMPARE(settings.value("vList").toList(), vList);
2217 QCOMPARE(settings.value("vList2").toList(), vList2);
2218 QCOMPARE(settings.value("vList3").toList(), vList3);
2219 QCOMPARE(settings.status(), QSettings::NoError);
2220 }
2221
2222 {
2223 QSettings settings("QtProject", "tst_qsettings");
2224 settings.setValue(key: "nullString", value: nullString);
2225 settings.setValue(key: "emptyString", value: emptyString);
2226 settings.setValue(key: "emptyList", value: emptyList);
2227 settings.setValue(key: "list", value: list);
2228 settings.setValue(key: "list2", value: list2);
2229 settings.setValue(key: "emptyVList", value: emptyVList);
2230 settings.setValue(key: "vList", value: vList);
2231 settings.setValue(key: "vList2", value: vList2);
2232 settings.setValue(key: "vList3", value: vList3);
2233 QCOMPARE(settings.status(), QSettings::NoError);
2234 }
2235 {
2236 QSettings settings("QtProject", "tst_qsettings");
2237 QCOMPARE(settings.value("nullString").toString(), nullString);
2238 QCOMPARE(settings.value("emptyString").toString(), emptyString);
2239 QCOMPARE(settings.value("emptyList").toStringList(), emptyList);
2240 QCOMPARE(settings.value("list").toStringList(), list);
2241 QCOMPARE(settings.value("list2").toStringList(), list2);
2242 QCOMPARE(settings.value("emptyVList").toList(), emptyVList);
2243 QCOMPARE(settings.value("vList").toList(), vList);
2244 QCOMPARE(settings.value("vList2").toList(), vList2);
2245 QCOMPARE(settings.value("vList3").toList(), vList3);
2246 QCOMPARE(settings.status(), QSettings::NoError);
2247 }
2248 QFile::remove(fileName: filename);
2249}
2250
2251void tst_QSettings::testEmptyKey()
2252{
2253 QSettings settings;
2254 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::value: Empty key passed");
2255 const QVariant value = settings.value(key: QString());
2256 QCOMPARE(value, QVariant());
2257 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::setValue: Empty key passed");
2258 settings.setValue(key: QString(), value);
2259}
2260
2261void tst_QSettings::testResourceFiles()
2262{
2263 QSettings settings(":/resourcefile.ini", QSettings::IniFormat);
2264 QCOMPARE(settings.status(), QSettings::NoError);
2265 QVERIFY(!settings.isWritable());
2266 QCOMPARE(settings.value("Field 1/Bottom").toInt(), 89);
2267 settings.setValue(key: "Field 1/Bottom", value: 90);
2268
2269 // the next two lines check the statu quo; another behavior would be possible
2270 QCOMPARE(settings.status(), QSettings::NoError);
2271 QCOMPARE(settings.value("Field 1/Bottom").toInt(), 90);
2272
2273 settings.sync();
2274 QCOMPARE(settings.status(), QSettings::AccessError);
2275 QCOMPARE(settings.value("Field 1/Bottom").toInt(), 90);
2276}
2277
2278void tst_QSettings::testRegistryShortRootNames()
2279{
2280#ifndef Q_OS_WIN
2281 QSKIP("This test is specific to the Windows registry only.");
2282#else
2283 QVERIFY(QSettings("HKEY_CURRENT_USER", QSettings::NativeFormat).childGroups() == QSettings("HKCU", QSettings::NativeFormat).childGroups());
2284 QVERIFY(QSettings("HKEY_LOCAL_MACHINE", QSettings::NativeFormat).childGroups() == QSettings("HKLM", QSettings::NativeFormat).childGroups());
2285 QVERIFY(QSettings("HKEY_CLASSES_ROOT", QSettings::NativeFormat).childGroups() == QSettings("HKCR", QSettings::NativeFormat).childGroups());
2286 QVERIFY(QSettings("HKEY_USERS", QSettings::NativeFormat).childGroups() == QSettings("HKU", QSettings::NativeFormat).childGroups());
2287#endif
2288}
2289
2290void tst_QSettings::testRegistry32And64Bit()
2291{
2292#if !defined (Q_OS_WIN) || defined(Q_OS_WINRT)
2293 QSKIP("This test is specific to the Windows registry.", SkipAll);
2294#else
2295
2296 const QString key("HKEY_LOCAL_MACHINE\\Software");
2297 const QString keyWow("HKEY_LOCAL_MACHINE\\Software\\Wow6432Node");
2298
2299#ifndef Q_OS_WIN64
2300 // This branch is taken at compile time if targeting 32-bit; it does not
2301 // necessarily mean that the OS running the test is 32-bit (it could be
2302 // e.g. 64-bit).
2303 QCOMPARE(QSettings(key, QSettings::NativeFormat).childGroups(),
2304 QSettings(key, QSettings::Registry32Format).childGroups());
2305
2306 // Detect whether we are running under 64-bit Windows.
2307 typedef BOOL (WINAPI *IsWow64ProcessPtr)(HANDLE hProcess, PBOOL Wow64Process);
2308 IsWow64ProcessPtr IsWow64Process = (IsWow64ProcessPtr)QLibrary::resolve(
2309 "kernel32.dll", "IsWow64Process");
2310
2311 if (IsWow64Process) {
2312 BOOL IsWow64 = FALSE;
2313 if (IsWow64Process(GetCurrentProcess(), &IsWow64) && IsWow64) {
2314 // The 64-bit registry's "Wow6432Node" key should match the 32-bit registry.
2315 // If we are not on 32-bit Windows, these should never be the same,
2316 // because the 64-bit registry has a "Wow6432Node" key.
2317 QCOMPARE(QSettings(keyWow, QSettings::Registry64Format).childGroups(),
2318 QSettings(key, QSettings::Registry32Format).childGroups());
2319 }
2320 }
2321#else
2322 // This branch is taken at compile time if targeting 64-bit; it does not
2323 // necessarily mean that the OS running the test is 64-bit (it could be
2324 // e.g. 128-bit).
2325 QCOMPARE(QSettings(key, QSettings::NativeFormat).childGroups(),
2326 QSettings(key, QSettings::Registry64Format).childGroups());
2327
2328 // The 64-bit registry's "Wow6432Node" key should match the 32-bit registry.
2329 QCOMPARE(QSettings(keyWow, QSettings::Registry64Format).childGroups(),
2330 QSettings(key, QSettings::Registry32Format).childGroups());
2331#endif
2332
2333#endif
2334}
2335
2336void tst_QSettings::trailingWhitespace()
2337{
2338 const QString path = settingsPath("trailingWhitespace");
2339 {
2340 QSettings s(path, QSettings::IniFormat);
2341 s.setValue(key: "trailingSpace", value: "x ");
2342 s.setValue(key: "trailingTab", value: "x\t");
2343 s.setValue(key: "trailingNewline", value: "x\n");
2344 }
2345 {
2346 QSettings s(path, QSettings::IniFormat);
2347 QCOMPARE(s.value("trailingSpace").toString(), QLatin1String("x "));
2348 QCOMPARE(s.value("trailingTab").toString(), QLatin1String("x\t"));
2349 QCOMPARE(s.value("trailingNewline").toString(), QLatin1String("x\n"));
2350 s.clear();
2351 }
2352}
2353
2354void tst_QSettings::fromFile_data()
2355{
2356 populateWithFormats();
2357}
2358
2359void tst_QSettings::fromFile()
2360{
2361 QFETCH(QSettings::Format, format);
2362
2363 const QString oldCur = QDir::currentPath();
2364 QString dataLocation = QStandardPaths::writableLocation(type: QStandardPaths::AppLocalDataLocation);
2365 QVERIFY(QDir::root().mkpath(dataLocation));
2366 QDir::setCurrent(dataLocation);
2367
2368 QFile::remove(fileName: "foo");
2369 QVERIFY(!QFile::exists("foo"));
2370
2371 QString path = "foo";
2372
2373#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
2374 if (format == QSettings::NativeFormat)
2375 path = "\\HKEY_CURRENT_USER\\Software\\foo";
2376#endif
2377
2378 QStringList strList = QStringList() << "hope" << "destiny" << "chastity";
2379
2380 {
2381 QSettings settings1(path, format);
2382 QVERIFY(settings1.allKeys().isEmpty());
2383
2384 settings1.setValue(key: "alpha", value: 1);
2385 settings1.setValue(key: "alpha", value: 2);
2386 settings1.setValue(key: "beta", value: strList);
2387
2388 QSettings settings2(path, format);
2389 QCOMPARE(settings2.value("alpha").toInt(), 2);
2390
2391 settings1.sync();
2392#if !defined(Q_OS_WIN)
2393 QVERIFY(QFile::exists("foo"));
2394#endif
2395 QCOMPARE(settings1.value("alpha").toInt(), 2);
2396 QCOMPARE(settings2.value("alpha").toInt(), 2);
2397
2398 settings2.setValue(key: "alpha", value: 3);
2399 settings2.setValue(key: "gamma/foo.bar", value: 4);
2400 QCOMPARE(settings1.value("alpha").toInt(), 3);
2401 QCOMPARE(settings2.value("alpha").toInt(), 3);
2402 QCOMPARE(settings1.value("beta").toStringList(), strList);
2403 QCOMPARE(settings2.value("beta").toStringList(), strList);
2404 QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4);
2405 QCOMPARE(settings2.value("gamma/foo.bar").toInt(), 4);
2406 }
2407
2408 {
2409 QSettings settings1(path, format);
2410 QCOMPARE(settings1.value("alpha").toInt(), 3);
2411 QCOMPARE(settings1.value("beta").toStringList(), strList);
2412 QCOMPARE(settings1.value("gamma/foo.bar").toInt(), 4);
2413 QCOMPARE(settings1.allKeys().size(), 3);
2414 }
2415
2416 QDir::setCurrent(oldCur);
2417}
2418
2419#ifdef QT_BUILD_INTERNAL
2420void tst_QSettings::setIniCodec()
2421{
2422 QByteArray expeContents4, expeContents5;
2423 QByteArray actualContents4, actualContents5;
2424
2425 {
2426 QFile inFile(":/resourcefile4.ini");
2427 inFile.open(flags: QIODevice::ReadOnly);
2428 expeContents4 = inFile.readAll();
2429 inFile.close();
2430 }
2431
2432 {
2433 QFile inFile(":/resourcefile5.ini");
2434 inFile.open(flags: QIODevice::ReadOnly);
2435 expeContents5 = inFile.readAll();
2436 inFile.close();
2437 }
2438
2439 {
2440 QSettings settings4(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP");
2441 settings4.setIniCodec("UTF-8");
2442 settings4.setValue(key: QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"), value: QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"));
2443 settings4.sync();
2444
2445 QSettings settings5(QSettings::IniFormat, QSettings::UserScope, "other.software.org", "KillerAPP");
2446 settings5.setIniCodec("ISO 8859-1");
2447 settings5.setValue(key: QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"), value: QLatin1String("Fa\xe7" "ade/QU\xc9" "BEC"));
2448 settings5.sync();
2449
2450 {
2451 QFile inFile(settings4.fileName());
2452 inFile.open(flags: QIODevice::ReadOnly | QIODevice::Text);
2453 actualContents4 = inFile.readAll();
2454 inFile.close();
2455 }
2456
2457 {
2458 QFile inFile(settings5.fileName());
2459 inFile.open(flags: QIODevice::ReadOnly | QIODevice::Text);
2460 actualContents5 = inFile.readAll();
2461 inFile.close();
2462 }
2463 }
2464
2465 QConfFile::clearCache();
2466
2467 QCOMPARE(actualContents4, expeContents4);
2468 QCOMPARE(actualContents5, expeContents5);
2469
2470 QSettings settings4(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP");
2471 settings4.setIniCodec("UTF-8");
2472 QSettings settings5(QSettings::IniFormat, QSettings::UserScope, "other.software.org", "KillerAPP");
2473 settings5.setIniCodec("Latin-1");
2474
2475 QCOMPARE(settings4.allKeys().count(), 1);
2476 QCOMPARE(settings5.allKeys().count(), 1);
2477
2478 QCOMPARE(settings4.allKeys().first(), settings5.allKeys().first());
2479 QCOMPARE(settings4.value(settings4.allKeys().first()).toString(),
2480 settings5.value(settings5.allKeys().first()).toString());
2481}
2482#endif
2483
2484static bool containsSubList(QStringList mom, QStringList son)
2485{
2486 for (int i = 0; i < son.size(); ++i) {
2487 if (!mom.contains(str: son.at(i)))
2488 return false;
2489 }
2490 return true;
2491}
2492
2493void tst_QSettings::testArrays_data()
2494{
2495 populateWithFormats();
2496}
2497
2498/*
2499 Tests beginReadArray(), beginWriteArray(), endArray(), and
2500 setArrayIndex().
2501*/
2502void tst_QSettings::testArrays()
2503{
2504 QFETCH(QSettings::Format, format);
2505
2506 {
2507 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP");
2508
2509 settings1.beginWriteArray(prefix: "foo/bar", size: 3);
2510 settings1.setValue(key: "bip", value: 1);
2511 settings1.setArrayIndex(0);
2512 settings1.setValue(key: "ene", value: 2);
2513 settings1.setValue(key: "due", value: 3);
2514 settings1.setValue(key: "rike", value: 4);
2515 settings1.setArrayIndex(1);
2516 settings1.setValue(key: "ene", value: 5);
2517 settings1.setValue(key: "due", value: 6);
2518 settings1.setValue(key: "rike", value: 7);
2519 settings1.setArrayIndex(2);
2520 settings1.setValue(key: "ene", value: 8);
2521 settings1.setValue(key: "due", value: 9);
2522 settings1.setValue(key: "rike", value: 10);
2523 settings1.endArray();
2524
2525 QStringList expectedList;
2526 expectedList
2527 << "foo/bar/bip"
2528 << "foo/bar/size"
2529 << "foo/bar/1/ene"
2530 << "foo/bar/1/due"
2531 << "foo/bar/1/rike"
2532 << "foo/bar/2/ene"
2533 << "foo/bar/2/due"
2534 << "foo/bar/2/rike"
2535 << "foo/bar/3/ene"
2536 << "foo/bar/3/due"
2537 << "foo/bar/3/rike";
2538 expectedList.sort();
2539
2540 QStringList actualList = settings1.allKeys();
2541 actualList.sort();
2542 QVERIFY(containsSubList(actualList, expectedList));
2543
2544 QCOMPARE(settings1.value("/foo/bar/bip").toInt(), 1);
2545 QCOMPARE(settings1.value("/foo/bar/1/ene").toInt(), 2);
2546 QCOMPARE(settings1.value("/foo/bar/1/due").toInt(), 3);
2547 QCOMPARE(settings1.value("/foo/bar/1/rike").toInt(), 4);
2548 QCOMPARE(settings1.value("/foo/bar/2/ene").toInt(), 5);
2549 QCOMPARE(settings1.value("/foo/bar/2/due").toInt(), 6);
2550 QCOMPARE(settings1.value("/foo/bar/2/rike").toInt(), 7);
2551 QCOMPARE(settings1.value("/foo/bar/3/ene").toInt(), 8);
2552 QCOMPARE(settings1.value("/foo/bar/3/due").toInt(), 9);
2553 QCOMPARE(settings1.value("/foo/bar/3/rike").toInt(), 10);
2554
2555 settings1.beginGroup(prefix: "/foo");
2556 int count = settings1.beginReadArray(prefix: "bar");
2557 QCOMPARE(count, 3);
2558 QCOMPARE(settings1.value("bip").toInt(), 1);
2559 settings1.setArrayIndex(0);
2560 QCOMPARE(settings1.value("ene").toInt(), 2);
2561 QCOMPARE(settings1.value("due").toInt(), 3);
2562 QCOMPARE(settings1.value("rike").toInt(), 4);
2563 QCOMPARE(settings1.allKeys().count(), 3);
2564 settings1.setArrayIndex(1);
2565 QCOMPARE(settings1.value("ene").toInt(), 5);
2566 QCOMPARE(settings1.value("due").toInt(), 6);
2567 QCOMPARE(settings1.value("rike").toInt(), 7);
2568 QCOMPARE(settings1.allKeys().count(), 3);
2569 settings1.setArrayIndex(2);
2570 QCOMPARE(settings1.value("ene").toInt(), 8);
2571 QCOMPARE(settings1.value("due").toInt(), 9);
2572 QCOMPARE(settings1.value("rike").toInt(), 10);
2573 QCOMPARE(settings1.allKeys().count(), 3);
2574
2575 settings1.endArray();
2576 settings1.endGroup();
2577 }
2578 /*
2579 Check that we get the arrays right when we load them again
2580 */
2581
2582 {
2583 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP");
2584
2585 QStringList expectedList;
2586 expectedList
2587 << "foo/bar/bip"
2588 << "foo/bar/size"
2589 << "foo/bar/1/ene"
2590 << "foo/bar/1/due"
2591 << "foo/bar/1/rike"
2592 << "foo/bar/2/ene"
2593 << "foo/bar/2/due"
2594 << "foo/bar/2/rike"
2595 << "foo/bar/3/ene"
2596 << "foo/bar/3/due"
2597 << "foo/bar/3/rike";
2598 expectedList.sort();
2599
2600 QStringList actualList = settings1.allKeys();
2601 actualList.sort();
2602 QVERIFY(containsSubList(actualList, expectedList));
2603
2604 QCOMPARE(settings1.value("/foo/bar/bip").toInt(), 1);
2605 QCOMPARE(settings1.value("/foo/bar/1/ene").toInt(), 2);
2606 QCOMPARE(settings1.value("/foo/bar/1/due").toInt(), 3);
2607 QCOMPARE(settings1.value("/foo/bar/1/rike").toInt(), 4);
2608 QCOMPARE(settings1.value("/foo/bar/2/ene").toInt(), 5);
2609 QCOMPARE(settings1.value("/foo/bar/2/due").toInt(), 6);
2610 QCOMPARE(settings1.value("/foo/bar/2/rike").toInt(), 7);
2611 QCOMPARE(settings1.value("/foo/bar/3/ene").toInt(), 8);
2612 QCOMPARE(settings1.value("/foo/bar/3/due").toInt(), 9);
2613 QCOMPARE(settings1.value("/foo/bar/3/rike").toInt(), 10);
2614
2615 settings1.beginGroup(prefix: "/foo");
2616 int count = settings1.beginReadArray(prefix: "bar");
2617 QCOMPARE(count, 3);
2618 QCOMPARE(settings1.value("bip").toInt(), 1);
2619 settings1.setArrayIndex(0);
2620 QCOMPARE(settings1.value("ene").toInt(), 2);
2621 QCOMPARE(settings1.value("due").toInt(), 3);
2622 QCOMPARE(settings1.value("rike").toInt(), 4);
2623 QCOMPARE(settings1.allKeys().count(), 3);
2624 settings1.setArrayIndex(1);
2625 QCOMPARE(settings1.value("ene").toInt(), 5);
2626 QCOMPARE(settings1.value("due").toInt(), 6);
2627 QCOMPARE(settings1.value("rike").toInt(), 7);
2628 QCOMPARE(settings1.allKeys().count(), 3);
2629 settings1.setArrayIndex(2);
2630 QCOMPARE(settings1.value("ene").toInt(), 8);
2631 QCOMPARE(settings1.value("due").toInt(), 9);
2632 QCOMPARE(settings1.value("rike").toInt(), 10);
2633 QCOMPARE(settings1.allKeys().count(), 3);
2634
2635 settings1.endArray();
2636 settings1.endGroup();
2637 }
2638 /*
2639 This code generates lots of warnings, but that's on purpose.
2640 Basically, we check that endGroup() can be used instead of
2641 endArray() and vice versa. This is not documented, but this
2642 is the behavior that we have chosen.
2643 */
2644 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::setArrayIndex: Missing beginArray()");
2645 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::setArrayIndex: Missing beginArray()");
2646 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::setArrayIndex: Missing beginArray()");
2647 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::setArrayIndex: Missing beginArray()");
2648 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::setArrayIndex: Missing beginArray()");
2649 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::endArray: Expected endGroup() instead");
2650 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::endGroup: Expected endArray() instead");
2651 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::endArray: Expected endGroup() instead");
2652 QTest::ignoreMessage(type: QtWarningMsg, message: "QSettings::endGroup: No matching beginGroup()");
2653
2654 QSettings settings1(format, QSettings::UserScope, "software.org", "KillerAPP");
2655 settings1.clear();
2656 settings1.beginGroup(prefix: "/alpha");
2657 QCOMPARE(settings1.group(), QString("alpha"));
2658 settings1.setArrayIndex(0);
2659 QCOMPARE(settings1.group(), QString("alpha"));
2660 settings1.setArrayIndex(1);
2661 QCOMPARE(settings1.group(), QString("alpha"));
2662 settings1.setArrayIndex(2);
2663 QCOMPARE(settings1.group(), QString("alpha"));
2664 settings1.beginGroup(prefix: "/beta");
2665 QCOMPARE(settings1.group(), QString("alpha/beta"));
2666 settings1.beginGroup(prefix: "");
2667 QCOMPARE(settings1.group(), QString("alpha/beta"));
2668 settings1.beginWriteArray(prefix: "DO", size: 4);
2669 QCOMPARE(settings1.value("size").toInt(), 4);
2670 QCOMPARE(settings1.group(), QString("alpha/beta/DO"));
2671 settings1.setArrayIndex(0);
2672 QCOMPARE(settings1.group(), QString("alpha/beta/DO/1"));
2673 settings1.setArrayIndex(1);
2674 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2"));
2675 settings1.beginGroup(prefix: "1");
2676 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1"));
2677 settings1.setArrayIndex(3);
2678 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1"));
2679 settings1.setArrayIndex(4);
2680 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1"));
2681 settings1.beginWriteArray(prefix: "RE");
2682 QVERIFY(!settings1.contains("size"));
2683 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE"));
2684 settings1.setArrayIndex(0);
2685 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE/1"));
2686 settings1.setArrayIndex(1);
2687 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1/RE/2"));
2688 settings1.endArray();
2689 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2/1"));
2690 settings1.endArray();
2691 QCOMPARE(settings1.group(), QString("alpha/beta/DO/2"));
2692 settings1.setArrayIndex(2);
2693 QCOMPARE(settings1.group(), QString("alpha/beta/DO/3"));
2694 settings1.endGroup();
2695 QCOMPARE(settings1.group(), QString("alpha/beta"));
2696 settings1.endGroup();
2697 QCOMPARE(settings1.group(), QString("alpha/beta"));
2698 settings1.endGroup();
2699 QCOMPARE(settings1.group(), QString("alpha"));
2700 settings1.endArray();
2701 QCOMPARE(settings1.group(), QString());
2702 settings1.endGroup();
2703 QCOMPARE(settings1.group(), QString());
2704 /*
2705 Now, let's make sure that things work well if an array
2706 is spread across multiple files.
2707 */
2708 int i;
2709
2710 settings1.clear();
2711 QSettings settings2(format, QSettings::UserScope, "software.org");
2712
2713 QStringList threeStrings;
2714 threeStrings << "Uno" << "Dos" << "Tres";
2715
2716 QStringList fiveStrings;
2717 fiveStrings << "alpha" << "beta" << "gamma" << "delta" << "epsilon";
2718
2719 settings1.beginWriteArray(prefix: "strings");
2720 for (i = threeStrings.size() - 1; i >= 0; --i) {
2721 settings1.setArrayIndex(i);
2722 settings1.setValue(key: "fileName", value: threeStrings.at(i));
2723 }
2724 settings1.endArray();
2725
2726 settings2.beginWriteArray(prefix: "strings");
2727 for (i = fiveStrings.size() - 1; i >= 0; --i) {
2728 settings2.setArrayIndex(i);
2729 settings2.setValue(key: "fileName", value: fiveStrings.at(i));
2730 }
2731 settings2.endArray();
2732
2733 int size1 = settings1.beginReadArray(prefix: "strings");
2734 QCOMPARE(size1, 3);
2735 QCOMPARE(settings1.value("size").toInt(), 3);
2736
2737 for (i = 0; i < size1; ++i) {
2738 settings1.setArrayIndex(i);
2739 QString str = settings1.value(key: "fileName").toString();
2740 QCOMPARE(str, threeStrings.at(i));
2741 }
2742 settings1.endArray();
2743
2744 int size2 = settings2.beginReadArray(prefix: "strings");
2745 QCOMPARE(size2, 5);
2746 QCOMPARE(settings2.value("size").toInt(), 5);
2747
2748 for (i = 0; i < size2; ++i) {
2749 settings2.setArrayIndex(i);
2750 QString str = settings2.value(key: "fileName").toString();
2751 QCOMPARE(str, fiveStrings.at(i));
2752 }
2753 settings2.endArray();
2754
2755 size1 = settings1.beginReadArray(prefix: "strings");
2756 QCOMPARE(size1, 3);
2757
2758 // accessing entries beyond the end of settings1 goes to settings2
2759 for (i = size1; i < size2; ++i) {
2760 settings1.setArrayIndex(i);
2761 QString str = settings1.value(key: "fileName").toString();
2762 QCOMPARE(str, fiveStrings.at(i));
2763 }
2764 settings1.endArray();
2765}
2766
2767#ifdef QT_BUILD_INTERNAL
2768static QByteArray iniEscapedKey(const QString &str)
2769{
2770 QByteArray result;
2771 QSettingsPrivate::iniEscapedKey(key: str, result);
2772 return result;
2773}
2774
2775static QString iniUnescapedKey(const QByteArray &ba)
2776{
2777 QString result;
2778 QSettingsPrivate::iniUnescapedKey(key: ba, from: 0, to: ba.size(), result);
2779 return result;
2780}
2781
2782static QByteArray iniEscapedStringList(const QStringList &strList)
2783{
2784 QByteArray result;
2785 QSettingsPrivate::iniEscapedStringList(strs: strList, result, codec: 0);
2786 return result;
2787}
2788
2789static QStringList iniUnescapedStringList(const QByteArray &ba)
2790{
2791 QStringList result;
2792 QString str;
2793#if QSETTINGS_P_H_VERSION >= 2
2794 bool isStringList = QSettingsPrivate::iniUnescapedStringList(str: ba, from: 0, to: ba.size(), stringResult&: str, stringListResult&: result
2795#if QSETTINGS_P_H_VERSION >= 3
2796 , codec: 0
2797#endif
2798 );
2799 if (!isStringList)
2800 result = QStringList(str);
2801#else
2802 QStringList *strList = QSettingsPrivate::iniUnescapedStringList(ba, 0, ba.size(), str);
2803 if (strList) {
2804 result = *strList;
2805 delete strList;
2806 } else {
2807 result = QStringList(str);
2808 }
2809#endif
2810 return result;
2811}
2812#endif
2813
2814QString escapeWeirdChars(const QString &s)
2815{
2816 QString result;
2817 bool escapeNextDigit = false;
2818
2819 for (int i = 0; i < s.length(); ++i) {
2820 QChar c = s.at(i);
2821 if (c.unicode() < ' ' || c.unicode() > '~'
2822 || (escapeNextDigit && c.unicode() >= '0' && c.unicode() <= 'f')) {
2823 result += QLatin1String("\\x") + QString::number(c.unicode(), base: 16);
2824 escapeNextDigit = true;
2825 } else {
2826 result += c;
2827 escapeNextDigit = false;
2828 }
2829 }
2830
2831 return result;
2832}
2833
2834#ifdef QT_BUILD_INTERNAL
2835void tst_QSettings::testEscapes()
2836{
2837 QSettings settings(QSettings::UserScope, "software.org", "KillerAPP");
2838
2839#define testEscapedKey(plainKey, escKey) \
2840 QCOMPARE(iniEscapedKey(plainKey), QByteArray(escKey)); \
2841 QCOMPARE(iniUnescapedKey(escKey), QString(plainKey));
2842
2843#define testUnescapedKey(escKey, plainKey, reescKey) \
2844 QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); \
2845 QCOMPARE(iniEscapedKey(plainKey), QByteArray(reescKey)); \
2846 QCOMPARE(iniUnescapedKey(reescKey), QString(plainKey));
2847
2848#define testEscapedStringList(plainStrList, escStrList) \
2849 { \
2850 QStringList plainList(plainStrList); \
2851 QByteArray escList(escStrList); \
2852 QCOMPARE(iniEscapedStringList(plainList), escList); \
2853 QCOMPARE(iniUnescapedStringList(escList), plainList); \
2854 } \
2855
2856
2857#define testUnescapedStringList(escStrList, plainStrList, reescStrList) \
2858 { \
2859 QStringList plainList(plainStrList); \
2860 QByteArray escList(escStrList); \
2861 QByteArray reescList(reescStrList); \
2862 QCOMPARE(iniUnescapedStringList(escList), plainList); \
2863 QCOMPARE(iniEscapedStringList(plainList), reescList); \
2864 QCOMPARE(iniUnescapedStringList(reescList), plainList); \
2865 } \
2866
2867
2868#define testVariant(val, escStr, func) \
2869 { \
2870 QVariant v(val); \
2871 QString s = QSettingsPrivate::variantToString(v); \
2872 QCOMPARE(s, escStr); \
2873 QCOMPARE(QVariant(QSettingsPrivate::stringToVariant(escStr)), v); \
2874 QVERIFY((val) == v.func()); \
2875 }
2876
2877#define testBadEscape(escStr, vStr) \
2878 { \
2879 QVariant v = QSettingsPrivate::stringToVariant(QString(escStr)); \
2880 QCOMPARE(v.toString(), QString(vStr)); \
2881 }
2882
2883 testEscapedKey("", "");
2884 testEscapedKey(" ", "%20");
2885 testEscapedKey(" 0123 abcd ", "%200123%20abcd%20");
2886 testEscapedKey("~!@#$%^&*()_+.-/\\=", "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D");
2887 testEscapedKey(QString() + QChar(0xabcd) + QChar(0x1234) + QChar(0x0081), "%UABCD%U1234%81");
2888 testEscapedKey(QString() + QChar(0xFE) + QChar(0xFF) + QChar(0x100) + QChar(0x101), "%FE%FF%U0100%U0101");
2889
2890 testUnescapedKey("", "", "");
2891 testUnescapedKey("%20", " ", "%20");
2892 testUnescapedKey("/alpha/beta", "/alpha/beta", "\\alpha\\beta");
2893 testUnescapedKey("\\alpha\\beta", "/alpha/beta", "\\alpha\\beta");
2894 testUnescapedKey("%5Calpha%5Cbeta", "\\alpha\\beta", "%5Calpha%5Cbeta");
2895 testUnescapedKey("%", "%", "%25");
2896 testUnescapedKey("%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%", QString("%f%!%%%%1x%x1%U%Uz%U123") + QChar(0x1234) + "\x12" + "34%",
2897 "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25");
2898
2899 testEscapedStringList("", "");
2900 testEscapedStringList(" ", "\" \"");
2901 testEscapedStringList(";", "\";\"");
2902 testEscapedStringList(",", "\",\"");
2903 testEscapedStringList("=", "\"=\"");
2904 testEscapedStringList("abc-def", "abc-def");
2905 testEscapedStringList(QChar(0) + QString("0"), "\\0\\x30");
2906 testEscapedStringList("~!@#$%^&*()_+.-/\\=", "\"~!@#$%^&*()_+.-/\\\\=\"");
2907 testEscapedStringList("~!@#$%^&*()_+.-/\\", "~!@#$%^&*()_+.-/\\\\");
2908 testEscapedStringList(QString("\x7F") + "12aFz", "\\x7f\\x31\\x32\\x61\\x46z");
2909 testEscapedStringList(QString(" \t\n\\n") + QChar(0x123) + QChar(0x4567), "\" \\t\\n\\\\n\\x123\\x4567\"");
2910 testEscapedStringList(QString("\a\b\f\n\r\t\v'\"?\001\002\x03\x04"), "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4");
2911 testEscapedStringList(QStringList() << "," << ";" << "a" << "ab, \tc, d ", "\",\", \";\", a, \"ab, \\tc, d \"");
2912
2913 /*
2914 Test .ini syntax that cannot be generated by QSettings (but can be entered by users).
2915 */
2916 testUnescapedStringList("", "", "");
2917 testUnescapedStringList("\"\"", "", "");
2918 testUnescapedStringList("\"abcdef\"", "abcdef", "abcdef");
2919 testUnescapedStringList("\"\\?\\'\\\"\"", "?'\"", "?'\\\"");
2920 testUnescapedStringList("\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\",
2921 QString() + QChar(0) + QChar(0) + QChar(0) + QChar(0) + QChar(1)
2922 + QChar(0111) + QChar(011111) + QChar(0) + QChar(0xCDEF) + "GH"
2923 + QChar(0x3456),
2924 "\\0\\0\\0\\0\\x1I\\x1249\\0\\xcdefGH\\x3456");
2925 testUnescapedStringList(QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16), "\f", "\\f");
2926 testUnescapedStringList("\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,",
2927 QStringList() << "a" << "bc " << " d" << "ef " << "" << "g" << "hi i"
2928 << "" << "" << "" << "",
2929 "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , ");
2930 testUnescapedStringList("a , b , c d , efg ",
2931 QStringList() << "a" << "b" << "c d" << "efg",
2932 "a, b, c d, efg");
2933
2934 // streaming qvariant into a string
2935 testVariant(QString("Hello World!"), QString("Hello World!"), toString);
2936 testVariant(QString("Hello, World!"), QString("Hello, World!"), toString);
2937 testVariant(QString("@Hello World!"), QString("@@Hello World!"), toString);
2938 testVariant(QString("@@Hello World!"), QString("@@@Hello World!"), toString);
2939#if QT_DEPRECATED_SINCE(5, 15)
2940 testVariant(QByteArray("Hello World!"), QString("@ByteArray(Hello World!)"), toString);
2941 testVariant(QByteArray("@Hello World!"), QString("@ByteArray(@Hello World!)"), toString);
2942#endif
2943 testVariant(QVariant(100), QString("100"), toString);
2944 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);
2945 testVariant(QRect(1, 2, 3, 4), QString("@Rect(1 2 3 4)"), toRect);
2946 testVariant(QSize(5, 6), QString("@Size(5 6)"), toSize);
2947 testVariant(QPoint(7, 8), QString("@Point(7 8)"), toPoint);
2948
2949 testBadEscape("", "");
2950 testBadEscape("@", "@");
2951 testBadEscape("@@", "@");
2952 testBadEscape("@@@", "@@");
2953 testBadEscape(" ", " ");
2954 testBadEscape("@Rect", "@Rect");
2955 testBadEscape("@Rect(", "@Rect(");
2956 testBadEscape("@Rect()", "@Rect()");
2957 testBadEscape("@Rect)", "@Rect)");
2958 testBadEscape("@Rect(1 2 3)", "@Rect(1 2 3)");
2959 testBadEscape("@@Rect(1 2 3)", "@Rect(1 2 3)");
2960}
2961#endif
2962
2963void tst_QSettings::testCaseSensitivity_data()
2964{
2965 populateWithFormats();
2966}
2967
2968void tst_QSettings::testCaseSensitivity()
2969{
2970 QFETCH(QSettings::Format, format);
2971
2972 for (int pass = 0; pass < 2; ++pass) {
2973 QSettings settings(format, QSettings::UserScope, "software.org", "KillerAPP");
2974 settings.beginGroup(prefix: "caseSensitivity");
2975
2976 bool cs = true;
2977#ifndef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
2978 switch (format) {
2979 case QSettings::NativeFormat:
2980#ifdef Q_OS_DARWIN
2981 cs = true;
2982#else
2983 cs = false;
2984#endif
2985 break;
2986 case QSettings::IniFormat:
2987 cs = false;
2988 break;
2989 case QSettings::CustomFormat1:
2990 cs = true;
2991 break;
2992 case QSettings::CustomFormat2:
2993 cs = false;
2994 break;
2995 default:
2996 ;
2997 }
2998#endif
2999
3000 if (pass == 0) {
3001 settings.setValue(key: "key 1", value: 1);
3002 settings.setValue(key: "KEY 1", value: 2);
3003 settings.setValue(key: "key 2", value: 3);
3004 }
3005
3006 for (int i = 0; i < 2; ++i) {
3007 QVERIFY(settings.contains("key 1"));
3008 QVERIFY(settings.contains("KEY 1"));
3009 QCOMPARE(settings.value("KEY 1").toInt(), 2);
3010/* QVERIFY(settings.allKeys().contains("/KEY 1"));
3011 QVERIFY(settings.allKeys().contains("/key 2")); */
3012
3013 if (cs) {
3014 QVERIFY(!settings.contains("kEy 1"));
3015 QCOMPARE(settings.value("key 1").toInt(), 1);
3016 QCOMPARE(settings.allKeys().size(), 3);
3017 QVERIFY(settings.allKeys().contains("key 1"));
3018 } else {
3019 QVERIFY(settings.contains("kEy 1"));
3020 QCOMPARE(settings.value("kEy 1").toInt(), 2);
3021 QCOMPARE(settings.value("key 1").toInt(), 2);
3022 QCOMPARE(settings.allKeys().size(), 2);
3023 }
3024
3025 settings.sync();
3026 }
3027
3028 settings.remove(key: "KeY 1");
3029
3030 if (cs) {
3031 QVERIFY(!settings.contains("KeY 1"));
3032 QVERIFY(settings.contains("key 1"));
3033 QVERIFY(settings.contains("KEY 1"));
3034 QCOMPARE(settings.value("key 1").toInt(), 1);
3035 QCOMPARE(settings.value("KEY 1").toInt(), 2);
3036 QCOMPARE(settings.allKeys().size(), 3);
3037 } else {
3038 QVERIFY(!settings.contains("KeY 1"));
3039 QVERIFY(!settings.contains("key 1"));
3040 QVERIFY(!settings.contains("KEY 1"));
3041 QCOMPARE(settings.allKeys().size(), 1);
3042 }
3043 settings.setValue(key: "KEY 1", value: 2);
3044 }
3045}
3046
3047#ifdef Q_OS_MAC
3048// Please write a fileName() test for the other platforms
3049void tst_QSettings::fileName()
3050{
3051 QSettings s1(QSettings::UserScope, "Apple", "Console");
3052 QSettings s2(QSettings::UserScope, "Apple");
3053 QSettings s3(QSettings::SystemScope, "Apple", "Console");
3054 QSettings s4(QSettings::SystemScope, "Apple");
3055
3056 QCOMPARE(s1.fileName(), QDir::homePath() + "/Library/Preferences/com.apple.Console.plist");
3057 QCOMPARE(s2.fileName(), QDir::homePath() + "/Library/Preferences/com.apple.plist");
3058 QCOMPARE(s3.fileName(), QString("/Library/Preferences/com.apple.Console.plist"));
3059 QCOMPARE(s4.fileName(), QString("/Library/Preferences/com.apple.plist"));
3060
3061 QSettings s5(QSettings::SystemScope, "Apple.com", "Console");
3062 QCOMPARE(s5.fileName(), QString("/Library/Preferences/com.apple.Console.plist"));
3063
3064 QSettings s6(QSettings::SystemScope, "apple.com", "Console");
3065 QCOMPARE(s6.fileName(), QString("/Library/Preferences/com.apple.Console.plist"));
3066
3067 QSettings s7(QSettings::SystemScope, "apple.Com", "Console");
3068 QCOMPARE(s7.fileName(), QString("/Library/Preferences/com.apple.Console.plist"));
3069
3070 QSettings s8(QSettings::SystemScope, "apple.fr", "Console");
3071 QCOMPARE(s8.fileName(), QString("/Library/Preferences/fr.apple.Console.plist"));
3072
3073 QSettings s9(QSettings::SystemScope, "apple.co.jp", "Console");
3074 QCOMPARE(s9.fileName(), QString("/Library/Preferences/jp.co.apple.Console.plist"));
3075
3076 QSettings s10(QSettings::SystemScope, "apple.org", "Console");
3077 QCOMPARE(s10.fileName(), QString("/Library/Preferences/org.apple.Console.plist"));
3078
3079 QSettings s11(QSettings::SystemScope, "apple.net", "Console");
3080 QCOMPARE(s11.fileName(), QString("/Library/Preferences/net.apple.Console.plist"));
3081
3082 QSettings s12(QSettings::SystemScope, "apple.museum", "Console");
3083 QCOMPARE(s12.fileName(), QString("/Library/Preferences/museum.apple.Console.plist"));
3084
3085 QSettings s13(QSettings::SystemScope, "apple.FR", "Console");
3086 QCOMPARE(s13.fileName(), QString("/Library/Preferences/fr.apple.Console.plist"));
3087
3088 QSettings s14(QSettings::SystemScope, "apple.mUseum", "Console");
3089 QCOMPARE(s14.fileName(), QString("/Library/Preferences/museum.apple.Console.plist"));
3090
3091 QSettings s15(QSettings::SystemScope, "apple.zz", "Console");
3092 QCOMPARE(s15.fileName(), QString("/Library/Preferences/zz.apple.Console.plist"));
3093
3094 QSettings s15_prime(QSettings::SystemScope, "apple.foo", "Console");
3095 QCOMPARE(s15_prime.fileName(), QString("/Library/Preferences/com.apple-foo.Console.plist"));
3096
3097 QSettings s16(QSettings::SystemScope, "apple.f", "Console");
3098 QCOMPARE(s16.fileName(), QString("/Library/Preferences/com.apple-f.Console.plist"));
3099
3100 QSettings s17(QSettings::SystemScope, "apple.", "Console");
3101 QCOMPARE(s17.fileName(), QString("/Library/Preferences/com.apple.Console.plist"));
3102
3103 QSettings s18(QSettings::SystemScope, "Foo, Inc.", "Console");
3104 QCOMPARE(s18.fileName(), QString("/Library/Preferences/com.foo-inc.Console.plist"));
3105
3106 QSettings s19(QSettings::SystemScope, "Foo, Inc.com", "Console");
3107 QCOMPARE(s19.fileName(), QString("/Library/Preferences/com.foo, inc.Console.plist"));
3108
3109 QSettings s20(QSettings::SystemScope, QLatin1String(" ") + QChar(0xbd) + QLatin1String("Foo//:/Barxxx Baz!()#@.com"), "Console");
3110 QCOMPARE(s20.fileName(), QLatin1String("/Library/Preferences/com. ") + QChar(0xbd) + QLatin1String("foo : barxxx baz!()#@.Console.plist"));
3111
3112 QSettings s21(QSettings::SystemScope, QLatin1String(" ") + QChar(0xbd) + QLatin1String("Foo//:/Bar,,, Baz!()#"), "Console");
3113 QCOMPARE(s21.fileName(), QString("/Library/Preferences/com.foo-bar-baz.Console.plist"));
3114}
3115#endif
3116
3117void tst_QSettings::isWritable_data()
3118{
3119 populateWithFormats();
3120}
3121
3122void tst_QSettings::isWritable()
3123{
3124 QFETCH(QSettings::Format, format);
3125
3126 {
3127 QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP");
3128 s1.setValue(key: "foo", value: 1);
3129 s1.sync();
3130 // that should create the file
3131 }
3132
3133 {
3134 QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP");
3135 QVERIFY(s1.isWritable());
3136 }
3137
3138 {
3139 QSettings s1(format, QSettings::SystemScope, "software.org", "KillerAPP");
3140 s1.setValue(key: "foo", value: 1);
3141 s1.sync();
3142 // that should create the file, *if* we have the permissions
3143 }
3144
3145 {
3146 QSettings s1(format, QSettings::SystemScope, "software.org", "KillerAPP");
3147 QSettings s2(format, QSettings::SystemScope, "software.org", "Something Different");
3148 QSettings s3(format, QSettings::SystemScope, "foo.org", "Something Different");
3149
3150 if (s1.status() == QSettings::NoError && s1.contains(key: "foo")) {
3151#if defined(Q_OS_MACX)
3152 QVERIFY(s1.isWritable());
3153 if (format == QSettings::NativeFormat) {
3154 QVERIFY(!s2.isWritable());
3155 QVERIFY(!s3.isWritable());
3156 } else {
3157 QVERIFY(s2.isWritable());
3158 QVERIFY(s3.isWritable());
3159 }
3160#else
3161 QVERIFY(s1.isWritable());
3162 QVERIFY(s2.isWritable());
3163 QVERIFY(s3.isWritable());
3164#endif
3165 } else {
3166 QVERIFY(!s1.isWritable());
3167 QVERIFY(!s2.isWritable());
3168 QVERIFY(!s3.isWritable());
3169 }
3170 }
3171}
3172
3173#ifdef QT_BUILD_INTERNAL
3174void tst_QSettings::childGroups_data()
3175{
3176 populateWithFormats();
3177}
3178#endif
3179
3180#ifdef QT_BUILD_INTERNAL
3181void tst_QSettings::childGroups()
3182{
3183 QFETCH(QSettings::Format, format);
3184
3185 const QSettings::Scope scope = m_canWriteNativeSystemSettings ? QSettings::SystemScope : QSettings::UserScope;
3186
3187 {
3188 QSettings settings(format, scope, "software.org");
3189 settings.setValue(key: "alpha", value: "1");
3190 settings.setValue(key: "alpha/a", value: "2");
3191 settings.setValue(key: "alpha/b", value: "3");
3192 settings.setValue(key: "alpha/c", value: "4");
3193 settings.setValue(key: "beta", value: "5");
3194 settings.setValue(key: "gamma", value: "6");
3195 settings.setValue(key: "gamma/d", value: "7");
3196 settings.setValue(key: "gamma/d/e", value: "8");
3197 settings.setValue(key: "gamma/f/g", value: "9");
3198 settings.setValue(key: "omicron/h/i/j/x", value: "10");
3199 settings.setValue(key: "omicron/h/i/k/y", value: "11");
3200 settings.setValue(key: "zeta/z", value: "12");
3201 }
3202
3203 for (int pass = 0; pass < 3; ++pass) {
3204 QConfFile::clearCache();
3205 QSettings settings(format, scope, "software.org");
3206 settings.setFallbacksEnabled(false);
3207 if (pass == 1) {
3208 settings.value(key: "gamma/d");
3209 } else if (pass == 2) {
3210 settings.value(key: "gamma");
3211 }
3212
3213 settings.beginGroup(prefix: "gamma");
3214 QStringList childGroups = settings.childGroups();
3215 childGroups.sort();
3216 QCOMPARE(childGroups, QStringList() << "d" << "f");
3217 settings.beginGroup(prefix: "d");
3218 QCOMPARE(settings.childGroups(), QStringList());
3219 settings.endGroup();
3220 settings.endGroup();
3221
3222 settings.beginGroup(prefix: "alpha");
3223 QCOMPARE(settings.childGroups(), QStringList());
3224 settings.endGroup();
3225
3226 settings.beginGroup(prefix: "d");
3227 QCOMPARE(settings.childGroups(), QStringList());
3228 settings.endGroup();
3229
3230 settings.beginGroup(prefix: "/omicron///h/i///");
3231 childGroups = settings.childGroups();
3232 childGroups.sort();
3233 QCOMPARE(childGroups, QStringList() << "j" << "k");
3234 settings.endGroup();
3235
3236 settings.beginGroup(prefix: "////");
3237 childGroups = settings.childGroups();
3238 childGroups.sort();
3239 QCOMPARE(childGroups, QStringList() << "alpha" << "gamma" << "omicron" << "zeta");
3240 settings.endGroup();
3241
3242 childGroups = settings.childGroups();
3243 childGroups.sort();
3244 QCOMPARE(childGroups, QStringList() << "alpha" << "gamma" << "omicron" << "zeta");
3245 }
3246}
3247#endif
3248
3249#ifdef QT_BUILD_INTERNAL
3250void tst_QSettings::childKeys_data()
3251{
3252 populateWithFormats();
3253}
3254#endif
3255
3256#ifdef QT_BUILD_INTERNAL
3257void tst_QSettings::childKeys()
3258{
3259 QFETCH(QSettings::Format, format);
3260
3261 const QSettings::Scope scope = m_canWriteNativeSystemSettings ? QSettings::SystemScope : QSettings::UserScope;
3262
3263 {
3264 QSettings settings(format, scope, "software.org");
3265 settings.setValue(key: "alpha", value: "1");
3266 settings.setValue(key: "alpha/a", value: "2");
3267 settings.setValue(key: "alpha/b", value: "3");
3268 settings.setValue(key: "alpha/c", value: "4");
3269 settings.setValue(key: "beta", value: "5");
3270 settings.setValue(key: "gamma", value: "6");
3271 settings.setValue(key: "gamma/d", value: "7");
3272 settings.setValue(key: "gamma/d/e", value: "8");
3273 settings.setValue(key: "gamma/f/g", value: "9");
3274 settings.setValue(key: "omicron/h/i/j/x", value: "10");
3275 settings.setValue(key: "omicron/h/i/k/y", value: "11");
3276 settings.setValue(key: "zeta/z", value: "12");
3277 }
3278
3279 for (int pass = 0; pass < 3; ++pass) {
3280 QConfFile::clearCache();
3281 QSettings settings(format, scope, "software.org");
3282 settings.setFallbacksEnabled(false);
3283 if (pass == 1) {
3284 settings.value(key: "gamma/d");
3285 } else if (pass == 2) {
3286 settings.value(key: "gamma");
3287 }
3288
3289 settings.beginGroup(prefix: "gamma");
3290 QCOMPARE(settings.childKeys(), QStringList() << "d");
3291 settings.beginGroup(prefix: "d");
3292 QCOMPARE(settings.childKeys(), QStringList() << "e");
3293 settings.endGroup();
3294 settings.endGroup();
3295
3296 settings.beginGroup(prefix: "alpha");
3297 QStringList childKeys = settings.childKeys();
3298 childKeys.sort();
3299 QCOMPARE(childKeys, QStringList() << "a" << "b" << "c");
3300 settings.endGroup();
3301
3302 settings.beginGroup(prefix: "d");
3303 QCOMPARE(settings.childKeys(), QStringList());
3304 settings.endGroup();
3305
3306 settings.beginGroup(prefix: "/omicron///h/i///");
3307 QCOMPARE(settings.childKeys(), QStringList());
3308 settings.endGroup();
3309
3310 settings.beginGroup(prefix: "////");
3311 childKeys = settings.childKeys();
3312 childKeys.sort();
3313 QCOMPARE(childKeys, QStringList() << "alpha" << "beta" << "gamma");
3314 settings.endGroup();
3315
3316 childKeys = settings.childKeys();
3317 childKeys.sort();
3318 QCOMPARE(childKeys, QStringList() << "alpha" << "beta" << "gamma");
3319 }
3320}
3321#endif
3322
3323#ifdef QT_BUILD_INTERNAL
3324void tst_QSettings::allKeys_data()
3325{
3326 populateWithFormats();
3327}
3328#endif
3329
3330#ifdef QT_BUILD_INTERNAL
3331void tst_QSettings::allKeys()
3332{
3333 QFETCH(QSettings::Format, format);
3334
3335 QStringList allKeys;
3336 allKeys << "alpha" << "alpha/a" << "alpha/b" << "alpha/c" << "beta" << "gamma" << "gamma/d"
3337 << "gamma/d/e" << "gamma/f/g" << "omicron/h/i/j/x" << "omicron/h/i/k/y" << "zeta/z";
3338
3339 const QSettings::Scope scope = m_canWriteNativeSystemSettings ? QSettings::SystemScope : QSettings::UserScope;
3340
3341 {
3342 QSettings settings(format, scope, "software.org");
3343 for (int i = 0; i < allKeys.size(); ++i)
3344 settings.setValue(key: allKeys.at(i), value: QString::number(i + 1));
3345 }
3346
3347 for (int pass = 0; pass < 3; ++pass) {
3348 QConfFile::clearCache();
3349 QSettings settings(format, scope, "software.org");
3350 settings.setFallbacksEnabled(false);
3351
3352 if (pass == 1) {
3353 settings.value(key: "gamma/d");
3354 } else if (pass == 2) {
3355 settings.value(key: "gamma");
3356 }
3357
3358 settings.beginGroup(prefix: "gamma");
3359 QStringList keys = settings.allKeys();
3360 keys.sort();
3361 QCOMPARE(keys, QStringList() << "d" << "d/e" << "f/g");
3362 settings.beginGroup(prefix: "d");
3363 QCOMPARE(settings.allKeys(), QStringList() << "e");
3364 settings.endGroup();
3365 settings.endGroup();
3366
3367 settings.beginGroup(prefix: "alpha");
3368 keys = settings.allKeys();
3369 keys.sort();
3370 QCOMPARE(keys, QStringList() << "a" << "b" << "c");
3371 settings.endGroup();
3372
3373 settings.beginGroup(prefix: "d");
3374 QCOMPARE(settings.allKeys(), QStringList());
3375 settings.endGroup();
3376
3377 settings.beginGroup(prefix: "/omicron///h/i///");
3378 keys = settings.allKeys();
3379 keys.sort();
3380 QCOMPARE(keys, QStringList() << "j/x" << "k/y");
3381 settings.endGroup();
3382
3383 settings.beginGroup(prefix: "////");
3384 keys = settings.allKeys();
3385 keys.sort();
3386 QCOMPARE(keys, allKeys);
3387 settings.endGroup();
3388
3389 keys = settings.allKeys();
3390 keys.sort();
3391 QCOMPARE(keys, allKeys);
3392 }
3393}
3394#endif
3395
3396void tst_QSettings::registerFormat()
3397{
3398 QSettings settings1(QSettings::IniFormat, QSettings::UserScope, "software.org", "KillerAPP");
3399 QSettings settings2(QSettings::CustomFormat1, QSettings::UserScope, "software.org", "KillerAPP");
3400
3401 QString fileName = settings1.fileName();
3402 fileName.chop(n: 3); // "ini";
3403 fileName.append(s: "custom1");
3404 QCOMPARE(settings2.fileName(), fileName);
3405
3406 // OK, let's see if it can read a generated file of a custom type
3407 // Beware: readCustom3File() and writeCustom3File() have unintuitive behavior
3408 // so we can test error handling
3409
3410 QSettings::Format custom3 = QSettings::registerFormat(extension: "custom3", readFunc: readCustom3File, writeFunc: writeCustom3File);
3411 QCOMPARE(custom3, QSettings::CustomFormat3);
3412
3413 QDir dir(settingsPath());
3414 QVERIFY(dir.mkpath("someDir"));
3415 QFile f(dir.path()+"/someDir/someSettings.custom3");
3416
3417 QVERIFY(f.open(QFile::WriteOnly));
3418 f.write(data: "OK");
3419 f.close();
3420
3421 {
3422 QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3);
3423 QCOMPARE(settings.status(), QSettings::NoError);
3424 QCOMPARE(settings.value("retval").toString(), QString("OK"));
3425 QVERIFY(settings.isWritable());
3426 }
3427
3428 QVERIFY(f.open(QFile::WriteOnly));
3429 f.write(data: "NotOK");
3430 f.close();
3431
3432 {
3433 QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3);
3434 QCOMPARE(settings.status(), QSettings::FormatError);
3435 QCOMPARE(settings.value("retval").toString(), QString());
3436 QVERIFY(settings.isWritable());
3437 }
3438
3439 QVERIFY(f.open(QFile::WriteOnly));
3440 f.write(data: "OK");
3441 f.close();
3442
3443 {
3444 QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat3);
3445 QCOMPARE(settings.status(), QSettings::NoError);
3446 settings.setValue(key: "zzz", value: "bar");
3447 settings.sync();
3448 QCOMPARE(settings.status(), QSettings::NoError);
3449
3450 settings.setValue(key: "retval", value: "NotOK");
3451 settings.sync();
3452 QCOMPARE(settings.status(), QSettings::AccessError);
3453
3454 QCOMPARE(settings.value("retval").toString(), QString("NotOK"));
3455 QVERIFY(settings.isWritable());
3456 }
3457
3458 {
3459 QSettings settings(settingsPath("someDir/someSettings.custom3"), QSettings::CustomFormat4);
3460 QCOMPARE(settings.status(), QSettings::AccessError);
3461 QVERIFY(!settings.isWritable());
3462 }
3463}
3464
3465void tst_QSettings::setPath()
3466{
3467#define TEST_PATH(doSet, ext, format, scope, path) \
3468 { \
3469 if (doSet) \
3470 QSettings::setPath(QSettings::format, QSettings::scope, settingsPath(path)); \
3471 QSettings settings1(QSettings::format, QSettings::scope, "software.org", "KillerAPP"); \
3472 QCOMPARE(QDir(settings1.fileName()), QDir(settingsPath(path) + QDir::separator() + "software.org" \
3473 + QDir::separator() + "KillerAPP." + ext)); \
3474 }
3475
3476 /*
3477 The first pass checks that setPath() works; the second
3478 path checks that it has no bad side effects.
3479 */
3480 for (int i = 0; i < 2; ++i) {
3481#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3482 TEST_PATH(i == 0, "conf", NativeFormat, UserScope, "alpha")
3483 TEST_PATH(i == 0, "conf", NativeFormat, SystemScope, "beta")
3484#endif
3485 TEST_PATH(i == 0, "ini", IniFormat, UserScope, "gamma")
3486 TEST_PATH(i == 0, "ini", IniFormat, SystemScope, "omicron")
3487 TEST_PATH(i == 0, "custom1", CustomFormat1, UserScope, "epsilon")
3488 TEST_PATH(i == 0, "custom1", CustomFormat1, SystemScope, "zeta")
3489 TEST_PATH(i == 0, "custom2", CustomFormat2, UserScope, "eta")
3490 TEST_PATH(i == 0, "custom2", CustomFormat2, SystemScope, "iota")
3491 }
3492}
3493
3494void tst_QSettings::setDefaultFormat()
3495{
3496 QCOMPARE(QSettings::defaultFormat(), QSettings::NativeFormat);
3497
3498 QSettings::setDefaultFormat(QSettings::CustomFormat1);
3499 QSettings settings1("org", "app");
3500 QSettings settings2(QSettings::SystemScope, "org", "app");
3501 QSettings settings3;
3502
3503 QCOMPARE(settings1.format(), QSettings::NativeFormat);
3504 QCOMPARE(settings2.format(), QSettings::NativeFormat);
3505 QCOMPARE(settings3.format(), QSettings::CustomFormat1);
3506
3507 QSettings::setDefaultFormat(QSettings::NativeFormat);
3508 QCOMPARE(QSettings::defaultFormat(), QSettings::NativeFormat);
3509
3510 QCOMPARE(settings1.format(), QSettings::NativeFormat);
3511 QCOMPARE(settings2.format(), QSettings::NativeFormat);
3512 QCOMPARE(settings3.format(), QSettings::CustomFormat1);
3513}
3514
3515void tst_QSettings::dontCreateNeedlessPaths()
3516{
3517 QString path;
3518 {
3519 QSettings settings(QSettings::IniFormat, QSettings::UserScope, "Hello", "Test");
3520 QVariant val = settings.value(key: "foo", defaultValue: "bar");
3521 path = settings.fileName();
3522 }
3523
3524 QFileInfo fileInfo(path);
3525 QVERIFY(!fileInfo.dir().exists());
3526}
3527
3528#if !defined(Q_OS_WIN) && !defined(QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER)
3529// This Qt build does not preserve ordering, as a code size optimization.
3530void tst_QSettings::dontReorderIniKeysNeedlessly()
3531{
3532
3533 /*
3534 This is a very strong test. It asserts that modifying
3535 resourcefile2.ini will lead to the exact contents of
3536 resourcefile3.ini. Right now it's run only on Unix
3537 systems, but that should be enough since the INI
3538 code (unlike this test) is platform-agnostic.
3539
3540 Things that are tested:
3541
3542 * keys are written in the same order that they were
3543 read in
3544
3545 * new keys are put at the end of their respective
3546 sections
3547 */
3548
3549 QFile inFile(":/resourcefile2.ini");
3550 inFile.open(QIODevice::ReadOnly);
3551 QByteArray contentsBefore = inFile.readAll();
3552 inFile.close();
3553
3554 QByteArray expectedContentsAfter;
3555
3556 {
3557 QFile inFile(":/resourcefile3.ini");
3558 inFile.open(QIODevice::ReadOnly);
3559 expectedContentsAfter = inFile.readAll();
3560 inFile.close();
3561 }
3562
3563 QString outFileName;
3564 QString outFileName2;
3565
3566 QTemporaryFile outFile;
3567 QVERIFY2(outFile.open(), qPrintable(outFile.errorString()));
3568 outFile.write(contentsBefore);
3569 outFileName = outFile.fileName();
3570 outFile.close();
3571
3572 QSettings settings(outFileName, QSettings::IniFormat);
3573 QCOMPARE(settings.status(), QSettings::NoError);
3574 QVERIFY(settings.isWritable());
3575
3576 settings.setValue("Field 1/Bottom", 90);
3577 settings.setValue("Field 1/x", 1);
3578 settings.setValue("Field 1/y", 1);
3579 settings.setValue("Field 1/width", 1);
3580 settings.setValue("Field 1/height", 1);
3581 settings.sync();
3582
3583 QFile outFile2(outFileName);
3584 QVERIFY(outFile2.open(QIODevice::ReadOnly));
3585 QCOMPARE(outFile2.readAll(), expectedContentsAfter);
3586 outFile2.close();
3587}
3588#endif
3589
3590void tst_QSettings::rainersSyncBugOnMac_data()
3591{
3592 ctor_data();
3593}
3594
3595void tst_QSettings::rainersSyncBugOnMac()
3596{
3597 QFETCH(QSettings::Format, format);
3598
3599#if defined(Q_OS_DARWIN) || defined(Q_OS_WINRT)
3600 if (format == QSettings::NativeFormat)
3601 QSKIP("Apple OSes do not support direct reads from and writes to .plist files, due to caching and background syncing. See QTBUG-34899.");
3602#endif
3603
3604 QString fileName;
3605
3606 {
3607 QSettings s1(format, QSettings::UserScope, "software.org", "KillerAPP");
3608 QCOMPARE(s1.value("key1", 5).toInt(), 5);
3609 fileName = s1.fileName();
3610 }
3611
3612 {
3613 QSettings s2(fileName, format);
3614 s2.setValue(key: "key1", value: 25);
3615 }
3616
3617 {
3618 QSettings s3(format, QSettings::UserScope, "software.org", "KillerAPP");
3619 QCOMPARE(s3.value("key1", 30).toInt(), 25);
3620 }
3621}
3622
3623void tst_QSettings::recursionBug()
3624{
3625 QPixmap pix(10,10);
3626 pix.fill(fillColor: "blue");
3627
3628 {
3629 QSettings settings(settingsPath("starrunner.ini"), QSettings::IniFormat);
3630 settings.setValue(key: "General/Pixmap", value: pix );
3631 }
3632}
3633
3634#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
3635
3636static DWORD readKeyType(HKEY handle, QStringView rSubKey)
3637{
3638 DWORD dataType;
3639 DWORD dataSize;
3640 LONG res = RegQueryValueEx(handle, reinterpret_cast<const wchar_t *>(rSubKey.utf16()),
3641 nullptr, &dataType, nullptr, &dataSize);
3642 return res == ERROR_SUCCESS ? dataType : 0;
3643}
3644
3645// This is a regression test for QTBUG-13249, where QSettings was storing
3646// signed integers as numeric values and unsigned integers as strings.
3647void tst_QSettings::consistentRegistryStorage()
3648{
3649 QSettings settings1(QSettings::UserScope, "software.org", "KillerAPP");
3650
3651 qint32 x = 1024;
3652 settings1.setValue("qint32_value", (qint32)x);
3653 QCOMPARE(settings1.value("qint32_value").toInt(), (qint32)1024);
3654 settings1.setValue("quint32_value", (quint32)x);
3655 QCOMPARE(settings1.value("quint32_value").toUInt(), (quint32)1024);
3656 settings1.setValue("qint64_value", (qint64)x);
3657 QCOMPARE(settings1.value("qint64_value").toLongLong(), (qint64)1024);
3658 settings1.setValue("quint64_value", (quint64)x);
3659 QCOMPARE(settings1.value("quint64_value").toULongLong(), (quint64)1024);
3660 settings1.sync();
3661
3662 QWinRegistryKey handle(HKEY_CURRENT_USER, LR"(Software\software.org\KillerAPP)");
3663 if (handle.isValid()) {
3664 QCOMPARE(readKeyType(handle, L"qint32_value"), DWORD(REG_DWORD));
3665 QCOMPARE(readKeyType(handle, L"quint32_value"), DWORD(REG_DWORD));
3666 QCOMPARE(readKeyType(handle, L"qint64_value"), DWORD(REG_QWORD));
3667 QCOMPARE(readKeyType(handle, L"quint64_value"), DWORD(REG_QWORD));
3668 RegCloseKey(handle);
3669 }
3670}
3671#endif
3672
3673#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(QT_NO_STANDARDPATHS)
3674QT_BEGIN_NAMESPACE
3675extern void clearDefaultPaths();
3676QT_END_NAMESPACE
3677#endif
3678void tst_QSettings::testXdg()
3679{
3680#if defined(QT_BUILD_INTERNAL) && defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID) && !defined(QT_NO_STANDARDPATHS)
3681 // Note: The XDG_CONFIG_DIRS test must be done before overriding the system path
3682 // by QSettings::setPath/setSystemIniPath (used in cleanupTestFiles()).
3683 clearDefaultPaths();
3684
3685 // Initialize the env. variable & populate testing files.
3686 const QStringList config_dirs = { settingsPath("xdg_1st"), settingsPath("xdg_2nd"), settingsPath("xdg_3rd") };
3687 qputenv(varName: "XDG_CONFIG_DIRS", value: config_dirs.join(sep: ':').toUtf8());
3688 QList<QSettings *> xdg_orgs, xdg_apps;
3689 for (const auto & dir : config_dirs) {
3690 xdg_orgs << new QSettings{dir + "/software.org.conf", QSettings::NativeFormat};
3691 xdg_apps << new QSettings{dir + "/software.org/KillerAPP.conf", QSettings::NativeFormat};
3692 }
3693 Q_ASSERT(config_dirs.size() == 3 && xdg_orgs.size() == 3 && xdg_apps.size() == 3);
3694 for (int i = 0; i < 3; ++i) {
3695 xdg_orgs[i]->setValue(key: "all", value: QString{"all_org%1"}.arg(a: i));
3696 xdg_apps[i]->setValue(key: "all", value: QString{"all_app%1"}.arg(a: i));
3697 xdg_orgs[i]->setValue(key: "all_only_org", value: QString{"all_only_org%1"}.arg(a: i));
3698 xdg_apps[i]->setValue(key: "all_only_app", value: QString{"all_only_app%1"}.arg(a: i));
3699
3700 if (i > 0) {
3701 xdg_orgs[i]->setValue(key: "from2nd", value: QString{"from2nd_org%1"}.arg(a: i));
3702 xdg_apps[i]->setValue(key: "from2nd", value: QString{"from2nd_app%1"}.arg(a: i));
3703 xdg_orgs[i]->setValue(key: "from2nd_only_org", value: QString{"from2nd_only_org%1"}.arg(a: i));
3704 xdg_apps[i]->setValue(key: "from2nd_only_app", value: QString{"from2nd_only_app%1"}.arg(a: i));
3705 }
3706
3707 if (i > 1) {
3708 xdg_orgs[i]->setValue(key: "from3rd", value: QString{"from3rd_org%1"}.arg(a: i));
3709 xdg_apps[i]->setValue(key: "from3rd", value: QString{"from3rd_app%1"}.arg(a: i));
3710 xdg_orgs[i]->setValue(key: "from3rd_only_org", value: QString{"from3rd_only_org%1"}.arg(a: i));
3711 xdg_apps[i]->setValue(key: "from3rd_only_app", value: QString{"from3rd_only_app%1"}.arg(a: i));
3712 }
3713 }
3714 qDeleteAll(c: xdg_apps);
3715 qDeleteAll(c: xdg_orgs);
3716
3717 // Do the test.
3718 QSettings app{QSettings::SystemScope, "software.org", "KillerAPP"}, org{QSettings::SystemScope, "software.org"};
3719
3720 QVERIFY(app.value("all").toString() == "all_app0");
3721 QVERIFY(org.value("all").toString() == "all_org0");
3722 QVERIFY(app.value("all_only_org").toString() == "all_only_org0");
3723 QVERIFY(org.value("all_only_org").toString() == "all_only_org0");
3724 QVERIFY(app.value("all_only_app").toString() == "all_only_app0");
3725 QVERIFY(org.value("all_only_app").toString() == QString{});
3726
3727 QVERIFY(app.value("from2nd").toString() == "from2nd_app1");
3728 QVERIFY(org.value("from2nd").toString() == "from2nd_org1");
3729 QVERIFY(app.value("from2nd_only_org").toString() == "from2nd_only_org1");
3730 QVERIFY(org.value("from2nd_only_org").toString() == "from2nd_only_org1");
3731 QVERIFY(app.value("from2nd_only_app").toString() == "from2nd_only_app1");
3732 QVERIFY(org.value("from2nd_only_app").toString() == QString{});
3733
3734 QVERIFY(app.value("from3rd").toString() == "from3rd_app2");
3735 QVERIFY(org.value("from3rd").toString() == "from3rd_org2");
3736 QVERIFY(app.value("from3rd_only_org").toString() == "from3rd_only_org2");
3737 QVERIFY(org.value("from3rd_only_org").toString() == "from3rd_only_org2");
3738 QVERIFY(app.value("from3rd_only_app").toString() == "from3rd_only_app2");
3739 QVERIFY(org.value("from3rd_only_app").toString() == QString{});
3740#else
3741 QSKIP("This test is performed in QT_BUILD_INTERNAL on Q_XDG_PLATFORM with use of standard paths only.");
3742#endif
3743}
3744
3745QTEST_MAIN(tst_QSettings)
3746#include "tst_qsettings.moc"
3747

source code of qtbase/tests/auto/corelib/io/qsettings/tst_qsettings.cpp