summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@qt.io>2016-10-03 18:41:30 +0200
committerTor Arne Vestbø <tor.arne.vestbo@qt.io>2016-10-18 14:35:08 +0000
commit4cb614c7abdaa2c5e2d0a75201d51aae01e6f8c4 (patch)
treea49ac5bc0b10054575dff75589b5c4f4ef411f98 /tests
parent158231e073eb2f94e7a6dfbf071dc2f34283321a (diff)
Apple OS: Handle QSetting strings with embedded zero-bytes
Saving strings with embedded zero-bytes (\0) as CFStrings would sometimes fail, and only write the part of the string leading up to the first zero-byte, instead of all the way to the final zero-terminator. This bug was revealed by the code-path that falls back to storing e.g. QTime as strings, via the helper method QSettingsPrivate::variantToString(). We now use the same approach as on platforms such as Windows and WinRT, where the string produced by variantToString() is checked for null-bytes, and if so, stored using a binary representation instead of as a string. For our case that means we fall back to CFData when detecting the null-byte. To separate strings from regular byte arrays, new logic has been added to variantToString() that wraps the null-byte strings in @String(). That way we can implement a fast-path when converting back from CFData, that doesn't go via the slow and lossy conversion via UTF8, and the resulting QVariant will be of type QVariant::ByteArray. The reason for using UTF-8 as the binary representation of the string is that in the case of storing a QByteArray("@foo") we need to still be able to convert it back to the same byte array, which doesn't work if the on-disk format is UTF-16. Task-number: QTBUG-56124 Change-Id: Iab2f71cf96cf3225de48dc5e71870d74b6dde1e8 Cherry-picked: 764f5bf48cc87f4c72550b853ab93b815454cd48 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/corelib/io/qsettings/tst_qsettings.cpp50
1 files changed, 49 insertions, 1 deletions
diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
index 19155cc3ad..f489b9b1d3 100644
--- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
+++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
@@ -162,6 +162,8 @@ private slots:
void testByteArray();
void iniCodec();
void bom();
+ void embeddedZeroByte_data();
+ void embeddedZeroByte();
private:
void cleanupTestFiles();
@@ -655,7 +657,6 @@ void tst_QSettings::testByteArray_data()
#ifndef QT_NO_COMPRESS
QTest::newRow("compressed") << qCompress(bytes);
#endif
- QTest::newRow("with \\0") << bytes + '\0' + bytes;
}
void tst_QSettings::testByteArray()
@@ -706,6 +707,53 @@ void tst_QSettings::bom()
QVERIFY(allkeys.contains("section2/foo2"));
}
+void tst_QSettings::embeddedZeroByte_data()
+{
+ QTest::addColumn<QVariant>("value");
+
+ QByteArray bytes("hello\0world", 11);
+
+ QTest::newRow("bytearray\\0") << QVariant(bytes);
+ QTest::newRow("string\\0") << QVariant(QString::fromLatin1(bytes.data(), bytes.size()));
+
+ bytes = QByteArray("@String(");
+
+ QTest::newRow("@bytearray") << QVariant(bytes);
+ QTest::newRow("@string") << QVariant(QString(bytes));
+
+ bytes = QByteArray("@String(\0test", 13);
+
+ QTest::newRow("@bytearray\\0") << QVariant(bytes);
+ QTest::newRow("@string\\0") << QVariant(QString::fromLatin1(bytes.data(), bytes.size()));
+}
+
+void tst_QSettings::embeddedZeroByte()
+{
+ QFETCH(QVariant, value);
+ {
+ QSettings settings("QtProject", "tst_qsettings");
+ settings.setValue(QTest::currentDataTag(), value);
+ }
+ {
+ QSettings settings("QtProject", "tst_qsettings");
+ QVariant outValue = settings.value(QTest::currentDataTag());
+
+ switch (value.type()) {
+ case QVariant::ByteArray:
+ QCOMPARE(outValue.toByteArray(), value.toByteArray());
+ break;
+ case QVariant::String:
+ QCOMPARE(outValue.toString(), value.toString());
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
+
+ if (value.toByteArray().contains(QChar::Null))
+ QVERIFY(outValue.toByteArray().contains(QChar::Null));
+ }
+}
+
void tst_QSettings::testErrorHandling_data()
{
QTest::addColumn<int>("filePerms"); // -1 means file should not exist