summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib
diff options
context:
space:
mode:
authorTarja Sundqvist <tarja.sundqvist@qt.io>2023-03-01 22:02:40 +0200
committerTarja Sundqvist <tarja.sundqvist@qt.io>2023-03-01 22:02:40 +0200
commit09b20bd9c157f8b7dde5f534a4d2366b27a33a2b (patch)
tree04bda80b1fe597d1b9bc183d9bee7fec5a1c8092 /tests/auto/corelib
parent22b60030490cf4b6418e9faab1559b658db1a887 (diff)
parenta4aeb081769cd0f5817c8e84b4740f315aa3b673 (diff)
Merge remote-tracking branch 'origin/tqtc/lts-6.2.6' into tqtc/lts-6.2-opensource
Diffstat (limited to 'tests/auto/corelib')
-rw-r--r--tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp6
-rw-r--r--tests/auto/corelib/io/qfile/tst_qfile.cpp8
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp77
-rw-r--r--tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp122
-rw-r--r--tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp79
-rw-r--r--tests/auto/corelib/serialization/json/tst_qtjson.cpp49
-rw-r--r--tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp12
-rw-r--r--tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp55
-rw-r--r--tests/auto/corelib/text/CMakeLists.txt5
-rw-r--r--tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp49
-rw-r--r--tests/auto/corelib/text/qlocale/tst_qlocale.cpp17
-rw-r--r--tests/auto/corelib/thread/qpromise/tst_qpromise.cpp20
-rw-r--r--tests/auto/corelib/thread/qthread/tst_qthread.cpp31
-rw-r--r--tests/auto/corelib/tools/qmap/tst_qmap.cpp7
14 files changed, 496 insertions, 41 deletions
diff --git a/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp b/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp
index 519c5fa88d..cb5d61aa2f 100644
--- a/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp
+++ b/tests/auto/corelib/global/qgetputenv/tst_qgetputenv.cpp
@@ -85,7 +85,11 @@ void tst_QGetPutEnv::getSetCheck()
QCOMPARE(sresult, QString());
#endif
- QVERIFY(qputenv(varName, QByteArray("supervalue")));
+ constexpr char varValueFullString[] = "supervalue123";
+ const auto varValueQBA = QByteArray::fromRawData(varValueFullString, sizeof varValueFullString - 4);
+ QCOMPARE(varValueQBA, "supervalue");
+
+ QVERIFY(qputenv(varName, varValueQBA));
QVERIFY(qEnvironmentVariableIsSet(varName));
QVERIFY(!qEnvironmentVariableIsEmpty(varName));
diff --git a/tests/auto/corelib/io/qfile/tst_qfile.cpp b/tests/auto/corelib/io/qfile/tst_qfile.cpp
index c67579967b..81924b3d10 100644
--- a/tests/auto/corelib/io/qfile/tst_qfile.cpp
+++ b/tests/auto/corelib/io/qfile/tst_qfile.cpp
@@ -2638,6 +2638,10 @@ void tst_QFile::unixPipe_data()
void tst_QFile::unixPipe()
{
+#ifdef Q_OS_ANDROID
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31)
+ QSKIP("Crashes on Android 12 (QTBUG-105736)");
+#endif
int pipes[2] = { -1, -1 };
QVERIFY2(pipe(pipes) == 0, qPrintable(qt_error_string()));
unixPipe_helper(pipes);
@@ -2647,6 +2651,10 @@ void tst_QFile::unixPipe()
void tst_QFile::socketPair()
{
+#ifdef Q_OS_ANDROID
+ if (QNativeInterface::QAndroidApplication::sdkVersion() >= 31)
+ QSKIP("Crashes on Android 12 (QTBUG-105736)");
+#endif
int pipes[2] = { -1, -1 };
QVERIFY2(socketpair(AF_UNIX, SOCK_STREAM, 0, pipes) == 0, qPrintable(qt_error_string()));
unixPipe_helper(pipes);
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index d639cdec26..f7e9ff375d 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -169,6 +169,7 @@ private slots:
void disconnectDisconnects();
void singleShotConnection();
void objectNameBinding();
+ void declarativeData();
};
struct QObjectCreatedOnShutdown
@@ -8160,5 +8161,81 @@ signals:
void aSignal5(const std::unique_ptr<const QObject> &);
};
+#ifdef QT_BUILD_INTERNAL
+/*
+ Since QObjectPrivate stores the declarativeData pointer in a union with the pointer
+ to the currently destroyed child, calls to the QtDeclarative handlers need to be
+ correctly guarded. QTBUG-105286
+*/
+namespace QtDeclarative {
+static QAbstractDeclarativeData *theData;
+
+static void destroyed(QAbstractDeclarativeData *data, QObject *)
+{
+ QCOMPARE(data, theData);
+}
+static void signalEmitted(QAbstractDeclarativeData *data, QObject *, int, void **)
+{
+ QCOMPARE(data, theData);
+}
+// we can't use QCOMPARE in the next two functions, as they don't return void
+static int receivers(QAbstractDeclarativeData *data, const QObject *, int)
+{
+ QTest::qCompare(data, theData, "data", "theData", __FILE__, __LINE__);
+ return 0;
+}
+static bool isSignalConnected(QAbstractDeclarativeData *data, const QObject *, int)
+{
+ QTest::qCompare(data, theData, "data", "theData", __FILE__, __LINE__);
+ return true;
+}
+
+class Object : public QObject
+{
+ Q_OBJECT
+public:
+ using QObject::QObject;
+ ~Object()
+ {
+ if (Object *p = static_cast<Object *>(parent()))
+ p->emitSignal();
+ }
+
+ void emitSignal()
+ {
+ emit theSignal();
+ }
+
+signals:
+ void theSignal();
+};
+
+}
+#endif
+
+void tst_QObject::declarativeData()
+{
+#ifdef QT_BUILD_INTERNAL
+ QScopedValueRollback destroyed(QAbstractDeclarativeData::destroyed,
+ QtDeclarative::destroyed);
+ QScopedValueRollback signalEmitted(QAbstractDeclarativeData::signalEmitted,
+ QtDeclarative::signalEmitted);
+ QScopedValueRollback receivers(QAbstractDeclarativeData::receivers,
+ QtDeclarative::receivers);
+ QScopedValueRollback isSignalConnected(QAbstractDeclarativeData::isSignalConnected,
+ QtDeclarative::isSignalConnected);
+
+ QtDeclarative::Object p;
+ QObjectPrivate *priv = QObjectPrivate::get(&p);
+ priv->declarativeData = QtDeclarative::theData = new QAbstractDeclarativeData;
+
+ connect(&p, &QtDeclarative::Object::theSignal, &p, []{
+ });
+
+ QtDeclarative::Object *child = new QtDeclarative::Object;
+ child->setParent(&p);
+#endif
+}
+
QTEST_MAIN(tst_QObject)
#include "tst_qobject.moc"
diff --git a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp
index 080b673ac9..8d6781fa2d 100644
--- a/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp
+++ b/tests/auto/corelib/kernel/qproperty/tst_qproperty.cpp
@@ -103,6 +103,8 @@ private slots:
void compatPropertySignals();
void noFakeDependencies();
+ void threadSafety();
+ void threadSafety2();
void bindablePropertyWithInitialization();
void noDoubleNotification();
@@ -1627,6 +1629,126 @@ void tst_QProperty::noFakeDependencies()
QCOMPARE(old, bindingFunctionCalled);
}
+struct ThreadSafetyTester : public QObject
+{
+ Q_OBJECT
+
+public:
+ ThreadSafetyTester(QObject *parent = nullptr) : QObject(parent) {}
+
+ Q_INVOKABLE bool hasCorrectStatus() const
+ {
+ return qGetBindingStorage(this)->status({}) == QtPrivate::getBindingStatus({});
+ }
+
+ Q_INVOKABLE bool bindingTest()
+ {
+ QProperty<QString> name(u"inThread"_qs);
+ bindableObjectName().setBinding([&]() -> QString { return name; });
+ name = u"inThreadChanged"_qs;
+ const bool nameChangedCorrectly = objectName() == name;
+ bindableObjectName().takeBinding();
+ return nameChangedCorrectly;
+ }
+};
+
+
+void tst_QProperty::threadSafety()
+{
+ QThread workerThread;
+ auto cleanup = qScopeGuard([&](){
+ QMetaObject::invokeMethod(&workerThread, "quit");
+ workerThread.wait();
+ });
+ QScopedPointer<ThreadSafetyTester> scopedObj1(new ThreadSafetyTester);
+ auto obj1 = scopedObj1.data();
+ auto child1 = new ThreadSafetyTester(obj1);
+ obj1->moveToThread(&workerThread);
+ const auto mainThreadBindingStatus = QtPrivate::getBindingStatus({});
+ QCOMPARE(qGetBindingStorage(child1)->status({}), nullptr);
+ workerThread.start();
+
+ bool correctStatus = false;
+ bool ok = QMetaObject::invokeMethod(obj1, "hasCorrectStatus", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, correctStatus));
+ QVERIFY(ok);
+ QVERIFY(correctStatus);
+
+ bool bindingWorks = false;
+ ok = QMetaObject::invokeMethod(obj1, "bindingTest", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, bindingWorks));
+ QVERIFY(ok);
+ QVERIFY(bindingWorks);
+
+ correctStatus = false;
+ ok = QMetaObject::invokeMethod(child1, "hasCorrectStatus", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, correctStatus));
+ QVERIFY(ok);
+ QVERIFY(correctStatus);
+
+ QScopedPointer scopedObj2(new ThreadSafetyTester);
+ auto obj2 = scopedObj2.data();
+ QCOMPARE(qGetBindingStorage(obj2)->status({}), mainThreadBindingStatus);
+
+ obj2->setObjectName("moved");
+ QCOMPARE(obj2->objectName(), "moved");
+
+ obj2->moveToThread(&workerThread);
+ correctStatus = false;
+ ok = QMetaObject::invokeMethod(obj2, "hasCorrectStatus", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(bool, correctStatus));
+
+ QVERIFY(ok);
+ QVERIFY(correctStatus);
+ // potentially unsafe, but should still work (no writes in owning thread)
+ QCOMPARE(obj2->objectName(), "moved");
+
+
+ QScopedPointer scopedObj3(new ThreadSafetyTester);
+ auto obj3 = scopedObj3.data();
+ obj3->setObjectName("moved");
+ QCOMPARE(obj3->objectName(), "moved");
+ obj3->moveToThread(nullptr);
+ QCOMPARE(obj2->objectName(), "moved");
+ obj3->setObjectName("moved again");
+ QCOMPARE(obj3->objectName(), "moved again");
+}
+
+class QPropertyUsingThread : public QThread
+{
+public:
+ QPropertyUsingThread(QObject **dest, QThread *destThread) : dest(dest), destThread(destThread) {}
+ void run() override
+ {
+ scopedObj1.reset(new ThreadSafetyTester());
+ scopedObj1->setObjectName("test");
+ QObject *child = new ThreadSafetyTester(scopedObj1.get());
+ child->setObjectName("child");
+ exec();
+ scopedObj1->moveToThread(destThread);
+ *dest = scopedObj1.release();
+ }
+ std::unique_ptr<ThreadSafetyTester> scopedObj1;
+ QObject **dest;
+ QThread *destThread;
+};
+
+void tst_QProperty::threadSafety2()
+{
+ std::unique_ptr<QObject> movedObj;
+ {
+ QObject *tmp = nullptr;
+ QPropertyUsingThread workerThread(&tmp, QThread::currentThread());
+ workerThread.start();
+ workerThread.quit();
+ workerThread.wait();
+ movedObj.reset(tmp);
+ }
+
+ QCOMPARE(movedObj->objectName(), "test");
+ QCOMPARE(movedObj->children().first()->objectName(), "child");
+}
+
struct CustomType
{
CustomType() = default;
diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
index d413bc726a..9fe7115d63 100644
--- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
+++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp
@@ -312,6 +312,10 @@ private slots:
void moveOperations();
void equalsWithoutMetaObject();
+ void constructFromIncompatibleMetaType_data();
+ void constructFromIncompatibleMetaType();
+ void copyNonDefaultConstructible();
+
private:
void dataStream_data(QDataStream::Version version);
void loadQVariantFromDataStream(QDataStream::Version version);
@@ -4734,6 +4738,11 @@ void tst_QVariant::metaEnums()
METAENUMS_TEST(MetaEnumTest_Enum5_value);
METAENUMS_TEST(MetaEnumTest_Enum6_value);
METAENUMS_TEST(MetaEnumTest_Enum8_value);
+
+#undef METAENUMS_TEST
+
+ testVariantMeta(Qt::RichText, &ok, "RichText");
+ testVariantMeta(Qt::Alignment(Qt::AlignBottom), &ok, "AlignBottom");
}
void tst_QVariant::nullConvert()
@@ -5132,5 +5141,75 @@ void tst_QVariant::equalsWithoutMetaObject()
QVERIFY(qobjectVariant != noMetaObjectVariant);
}
+struct NonDefaultConstructible
+{
+ NonDefaultConstructible(int i) :i(i) {}
+ int i;
+ friend bool operator==(NonDefaultConstructible l, NonDefaultConstructible r)
+ { return l.i == r.i; }
+};
+
+template <> char *QTest::toString<NonDefaultConstructible>(const NonDefaultConstructible &ndc)
+{
+ return qstrdup('{' + QByteArray::number(ndc.i) + '}');
+}
+
+struct Indestructible
+{
+ Indestructible() {}
+ Indestructible(const Indestructible &) {}
+ Indestructible &operator=(const Indestructible &) { return *this; }
+private:
+ ~Indestructible() {}
+};
+
+void tst_QVariant::constructFromIncompatibleMetaType_data()
+{
+ QTest::addColumn<QMetaType>("type");
+ auto addRow = [](QMetaType meta) {
+ QTest::newRow(meta.name()) << meta;
+ };
+ addRow(QMetaType::fromType<void>());
+ addRow(QMetaType::fromType<NonDefaultConstructible>());
+ addRow(QMetaType::fromType<QObject>());
+ addRow(QMetaType::fromType<Indestructible>());
+}
+
+void tst_QVariant::constructFromIncompatibleMetaType()
+{
+ QFETCH(QMetaType, type);
+ // in that case, we run into a different condition (size == 0), and do not warn
+ if (QTest::currentDataTag() != QLatin1String("void"))
+ QTest::ignoreMessage(
+ QtWarningMsg,
+ "QVariant: Provided metatype does not support destruction, copy and default construction");
+ QVariant var(type, nullptr);
+ QVERIFY(!var.isValid());
+ QVERIFY(!var.metaType().isValid());
+
+ QVariant regular(1.0);
+ QVERIFY(!var.canView(type));
+ QVERIFY(!var.canConvert(type));
+ QVERIFY(!QVariant(regular).convert(type));
+}
+
+void tst_QVariant::copyNonDefaultConstructible()
+{
+ NonDefaultConstructible ndc(42);
+ QVariant var(QMetaType::fromType<NonDefaultConstructible>(), &ndc);
+ QVERIFY(var.isDetached());
+ QCOMPARE(var.metaType(), QMetaType::fromType<NonDefaultConstructible>());
+ QVERIFY(var.constData() != &ndc);
+
+ // qvariant_cast<T> and QVariant::value<T> don't compile
+ QCOMPARE(*static_cast<const NonDefaultConstructible *>(var.constData()), ndc);
+
+ QVariant var2 = var;
+ var2.detach(); // force another copy
+ QVERIFY(var2.isDetached());
+ QVERIFY(var2.constData() != var.constData());
+ QCOMPARE(var2, var);
+}
+
QTEST_MAIN(tst_QVariant)
#include "tst_qvariant.moc"
diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
index fa03bfa7b1..a5c3907b0b 100644
--- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
@@ -1,6 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
+** Copyright (C) 2021 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the test suite of the Qt Toolkit.
@@ -401,7 +402,7 @@ void tst_QtJson::testNumbers_2()
QVERIFY2(floatValues_1[index - 1] == (floatValues_1[index] * 2), QString("Value should be double adjacent value at index %1").arg(index).toLatin1());
}
} else {
- QSKIP("Skipping 'denorm' as this type lacks denormals on this system");
+ qInfo("Skipping denormal test as this system's double type lacks support");
}
}
@@ -2286,30 +2287,28 @@ void tst_QtJson::parseNumbers()
QCOMPARE(val.toDouble(), numbers[i].n);
}
}
- {
- if constexpr (std::numeric_limits<double>::has_denorm == std::denorm_present) {
- Numbers numbers [] = {
- { "1.1e-308", 1.1e-308 },
- { "-1.1e-308", -1.1e-308 }
- };
- int size = sizeof(numbers)/sizeof(Numbers);
- for (int i = 0; i < size; ++i) {
- QByteArray json = "[ ";
- json += numbers[i].str;
- json += " ]";
- QJsonDocument doc = QJsonDocument::fromJson(json);
- QVERIFY(!doc.isEmpty());
- QCOMPARE(doc.isArray(), true);
- QCOMPARE(doc.isObject(), false);
- QJsonArray array = doc.array();
- QCOMPARE(array.size(), 1);
- QJsonValue val = array.at(0);
- QCOMPARE(val.type(), QJsonValue::Double);
- QCOMPARE(val.toDouble(), numbers[i].n);
- }
- } else {
- QSKIP("Skipping 'denorm' as this type lacks denormals on this system");
+ if constexpr (std::numeric_limits<double>::has_denorm == std::denorm_present) {
+ Numbers numbers [] = {
+ { "1.1e-308", 1.1e-308 },
+ { "-1.1e-308", -1.1e-308 }
+ };
+ int size = sizeof(numbers)/sizeof(Numbers);
+ for (int i = 0; i < size; ++i) {
+ QByteArray json = "[ ";
+ json += numbers[i].str;
+ json += " ]";
+ QJsonDocument doc = QJsonDocument::fromJson(json);
+ QVERIFY(!doc.isEmpty());
+ QCOMPARE(doc.isArray(), true);
+ QCOMPARE(doc.isObject(), false);
+ QJsonArray array = doc.array();
+ QCOMPARE(array.size(), 1);
+ QJsonValue val = array.at(0);
+ QCOMPARE(val.type(), QJsonValue::Double);
+ QCOMPARE(val.toDouble(), numbers[i].n);
}
+ } else {
+ qInfo("Skipping denormal test as this system's double type lacks support");
}
}
diff --git a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
index 511d8f957f..a2fbd9d54d 100644
--- a/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
+++ b/tests/auto/corelib/serialization/qdatastream/tst_qdatastream.cpp
@@ -1228,15 +1228,15 @@ void tst_QDataStream::readQCursor(QDataStream *s)
QCOMPARE(d5.hotSpot(), test.hotSpot());
// Comparing non-null QBitmaps will fail. Upcast them first to pass.
- QCOMPARE(d5.bitmap(Qt::ReturnByValue).isNull(), test.bitmap(Qt::ReturnByValue).isNull());
+ QCOMPARE(d5.bitmap().isNull(), test.bitmap().isNull());
QCOMPARE(
- static_cast<QPixmap>(d5.bitmap(Qt::ReturnByValue)),
- static_cast<QPixmap>(test.bitmap(Qt::ReturnByValue))
+ static_cast<QPixmap>(d5.bitmap()),
+ static_cast<QPixmap>(test.bitmap())
);
- QCOMPARE(d5.mask(Qt::ReturnByValue).isNull(), test.mask(Qt::ReturnByValue).isNull());
+ QCOMPARE(d5.mask().isNull(), test.mask().isNull());
QCOMPARE(
- static_cast<QPixmap>(d5.mask(Qt::ReturnByValue)),
- static_cast<QPixmap>(test.mask(Qt::ReturnByValue))
+ static_cast<QPixmap>(d5.mask()),
+ static_cast<QPixmap>(test.mask())
);
}
#endif
diff --git a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp
index 9e8bcfaea2..a6bac5eafc 100644
--- a/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp
+++ b/tests/auto/corelib/serialization/qtextstream/tst_qtextstream.cpp
@@ -37,6 +37,7 @@
#include <QDebug>
#include <QElapsedTimer>
#include <QFile>
+#include <QTemporaryFile>
#include <QStringConverter>
#include <QTcpSocket>
#include <QTemporaryDir>
@@ -225,6 +226,9 @@ private slots:
void textModeOnEmptyRead();
+ void autodetectUnicode_data();
+ void autodetectUnicode();
+
private:
void generateLineData(bool for_QString);
void generateAllData(bool for_QString);
@@ -3032,6 +3036,57 @@ void tst_QTextStream::textModeOnEmptyRead()
QVERIFY(file.isTextModeEnabled());
}
+void tst_QTextStream::autodetectUnicode_data()
+{
+ QTest::addColumn<QStringConverter::Encoding>("encoding");
+ QTest::newRow("Utf8") << QStringConverter::Utf8;
+ QTest::newRow("Utf16BE") << QStringConverter::Utf16BE;
+ QTest::newRow("Utf16LE") << QStringConverter::Utf16LE;
+ QTest::newRow("Utf32BE") << QStringConverter::Utf32BE;
+ QTest::newRow("Utf32LE") << QStringConverter::Utf32LE;
+}
+
+void tst_QTextStream::autodetectUnicode()
+{
+ QFETCH(QStringConverter::Encoding, encoding);
+
+ QTemporaryFile file;
+ QVERIFY(file.open());
+
+ QString original("HelloWorldđź‘‹");
+
+ {
+ QTextStream out(&file);
+ out.setGenerateByteOrderMark(true);
+ out.setEncoding(encoding);
+ out << original;
+ }
+ file.seek(0);
+ {
+ QTextStream in(&file);
+ QString actual;
+ in >> actual;
+ QCOMPARE(actual, original);
+ QCOMPARE(in.encoding(), encoding);
+ }
+ file.seek(0);
+ // Again, but change order of calls to QTextStream...
+ {
+ QTextStream out(&file);
+ out.setEncoding(encoding);
+ out.setGenerateByteOrderMark(true);
+ out << original;
+ }
+ file.seek(0);
+ {
+ QTextStream in(&file);
+ QString actual;
+ in >> actual;
+ QCOMPARE(actual, original);
+ QCOMPARE(in.encoding(), encoding);
+ }
+}
+
// ------------------------------------------------------------------------------
diff --git a/tests/auto/corelib/text/CMakeLists.txt b/tests/auto/corelib/text/CMakeLists.txt
index 40bacf2037..c1af682836 100644
--- a/tests/auto/corelib/text/CMakeLists.txt
+++ b/tests/auto/corelib/text/CMakeLists.txt
@@ -22,7 +22,4 @@ add_subdirectory(qstringmatcher)
add_subdirectory(qstringtokenizer)
add_subdirectory(qstringview)
add_subdirectory(qtextboundaryfinder)
-# QTBUG-87414 # special case
-if(NOT ANDROID)
- add_subdirectory(qlocale)
-endif()
+add_subdirectory(qlocale)
diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
index 08c4086955..72a6427930 100644
--- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
+++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
@@ -35,6 +35,9 @@
#include <limits.h>
#include <private/qtools_p.h>
+#include <stdexcept>
+#include <string_view>
+
class tst_QByteArray : public QObject
{
Q_OBJECT
@@ -45,8 +48,8 @@ private slots:
void swap();
void qChecksum_data();
void qChecksum();
- void qCompress_data();
#ifndef QT_NO_COMPRESS
+ void qCompress_data();
void qCompress();
void qUncompressCorruptedData_data();
void qUncompressCorruptedData();
@@ -62,6 +65,7 @@ private slots:
void split();
void base64_data();
void base64();
+ void base64_2GiB();
void fromBase64_data();
void fromBase64();
void qvsnprintf();
@@ -187,7 +191,7 @@ QByteArray verifyZeroTermination(const QByteArray &ba)
if (!baDataPtr->isMutable())
return ba;
- int baSize = ba.size();
+ qsizetype baSize = ba.size();
char baTerminator = ba.constData()[baSize];
if ('\0' != baTerminator)
return QString::fromUtf8(
@@ -268,6 +272,7 @@ void tst_QByteArray::qChecksum()
QCOMPARE(::qChecksum(QByteArrayView(data.constData(), len), standard), static_cast<quint16>(checksum));
}
+#ifndef QT_NO_COMPRESS
void tst_QByteArray::qCompress_data()
{
QTest::addColumn<QByteArray>("ba");
@@ -294,7 +299,6 @@ void tst_QByteArray::qCompress_data()
QTest::newRow( "04" ) << file.readAll();
}
-#ifndef QT_NO_COMPRESS
void tst_QByteArray::qCompress()
{
QFETCH( QByteArray, ba );
@@ -618,6 +622,45 @@ void tst_QByteArray::base64()
QCOMPARE(arr64, base64urlnoequals);
}
+void tst_QByteArray::base64_2GiB()
+{
+#ifdef Q_OS_ANDROID
+ QSKIP("Android kills the test when using too much memory");
+#endif
+ if constexpr (sizeof(qsizetype) > sizeof(int)) {
+ try {
+ constexpr qint64 GiB = 1024 * 1024 * 1024;
+ static_assert((2 * GiB + 1) % 3 == 0);
+ const char inputChar = '\0'; // all-NULs encode as
+ const char outputChar = 'A'; // all-'A's
+ const qint64 inputSize = 2 * GiB + 1;
+ const qint64 outputSize = inputSize / 3 * 4;
+ const auto sv = [](const QByteArray &ba) {
+ return std::string_view{ba.data(), size_t(ba.size())};
+ };
+ QByteArray output;
+ {
+ const QByteArray input(inputSize, inputChar);
+ output = input.toBase64();
+ QCOMPARE(output.size(), outputSize);
+ QCOMPARE(sv(output).find_first_not_of(outputChar),
+ std::string_view::npos);
+ }
+ {
+ auto r = QByteArray::fromBase64Encoding(output);
+ QCOMPARE(r.decodingStatus, QByteArray::Base64DecodingStatus::Ok);
+ QCOMPARE(r.decoded.size(), inputSize);
+ QCOMPARE(sv(r.decoded).find_first_not_of(inputChar),
+ std::string_view::npos);
+ }
+ } catch (const std::bad_alloc &) {
+ QSKIP("Could not allocate enough RAM.");
+ }
+ } else {
+ QSKIP("This is a 64-bit only test");
+ }
+}
+
//different from the previous test as the input are invalid
void tst_QByteArray::fromBase64_data()
{
diff --git a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
index 8a81151ea6..2dd4620718 100644
--- a/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
+++ b/tests/auto/corelib/text/qlocale/tst_qlocale.cpp
@@ -3103,7 +3103,12 @@ public:
QVariant query(QueryType type, QVariant /*in*/) const override
{
- return type == UILanguages ? QVariant(QStringList{m_name}) : QVariant();
+ if (type == UILanguages) {
+ if (m_name == u"en-DE") // QTBUG-104930: simulate macOS's list not including m_name.
+ return QVariant(QStringList{QStringLiteral("en-GB"), QStringLiteral("de-DE")});
+ return QVariant(QStringList{m_name});
+ }
+ return QVariant();
}
QLocale fallbackLocale() const override
@@ -3132,6 +3137,12 @@ void tst_QLocale::systemLocale_data()
QTest::addRow("ukrainian")
<< QString("uk") << QLocale::Ukrainian
<< QStringList{QStringLiteral("uk"), QStringLiteral("uk-UA"), QStringLiteral("uk-Cyrl-UA")};
+ QTest::addRow("english-germany")
+ << QString("en-DE") << QLocale::English
+ // First two were missed out before fix to QTBUG-104930:
+ << QStringList{QStringLiteral("en-DE"), QStringLiteral("en-Latn-DE"),
+ QStringLiteral("en-GB"), QStringLiteral("en-Latn-GB"),
+ QStringLiteral("de-DE"), QStringLiteral("de"), QStringLiteral("de-Latn-DE")};
QTest::addRow("german")
<< QString("de") << QLocale::German
<< QStringList{QStringLiteral("de"), QStringLiteral("de-DE"), QStringLiteral("de-Latn-DE")};
@@ -3156,7 +3167,11 @@ void tst_QLocale::systemLocale()
MySystemLocale sLocale(name);
QCOMPARE(QLocale().language(), language);
QCOMPARE(QLocale::system().language(), language);
+ auto reporter = qScopeGuard([]() {
+ qDebug("\n\t%s", qPrintable(QLocale::system().uiLanguages().join(u"\n\t")));
+ });
QCOMPARE(QLocale::system().uiLanguages(), uiLanguages);
+ reporter.dismiss();
}
QCOMPARE(QLocale(), originalLocale);
diff --git a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
index 5c20287e89..e2c92a494b 100644
--- a/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
+++ b/tests/auto/corelib/thread/qpromise/tst_qpromise.cpp
@@ -65,6 +65,7 @@ private slots:
#endif
void cancelWhenReassigned();
void cancelWhenDestroyedWithoutStarting();
+ void cancelWhenDestroyedRunsContinuations();
void finishWhenSwapped();
void cancelWhenMoved();
void waitUntilResumed();
@@ -519,6 +520,25 @@ void tst_QPromise::cancelWhenDestroyedWithoutStarting()
QVERIFY(future.isFinished());
}
+void tst_QPromise::cancelWhenDestroyedRunsContinuations()
+{
+ QFuture<void> future;
+ bool onCanceledCalled = false;
+ bool thenCalled = false;
+ {
+ QPromise<void> promise;
+ future = promise.future();
+ future.then([&] {
+ thenCalled = true;
+ }).onCanceled([&] {
+ onCanceledCalled = true;
+ });
+ }
+ QVERIFY(future.isFinished());
+ QVERIFY(!thenCalled);
+ QVERIFY(onCanceledCalled);
+}
+
void tst_QPromise::finishWhenSwapped()
{
#if !QT_CONFIG(cxx11_future)
diff --git a/tests/auto/corelib/thread/qthread/tst_qthread.cpp b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
index a396ebffc2..0369201a7c 100644
--- a/tests/auto/corelib/thread/qthread/tst_qthread.cpp
+++ b/tests/auto/corelib/thread/qthread/tst_qthread.cpp
@@ -41,6 +41,8 @@
#include <qdebug.h>
#include <qmetaobject.h>
#include <qscopeguard.h>
+#include <private/qobject_p.h>
+#include <private/qthread_p.h>
#ifdef Q_OS_UNIX
#include <pthread.h>
@@ -90,6 +92,7 @@ private slots:
void adoptedThreadExecFinished();
void adoptMultipleThreads();
void adoptMultipleThreadsOverlap();
+ void adoptedThreadBindingStatus();
void exitAndStart();
void exitAndExec();
@@ -112,6 +115,8 @@ private slots:
void create();
void threadIdReuse();
+
+ void bindingListCleanupAfterDelete();
};
enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute };
@@ -951,6 +956,20 @@ void tst_QThread::adoptMultipleThreadsOverlap()
QCOMPARE(recorder.activationCount.loadRelaxed(), numThreads);
}
+void tst_QThread::adoptedThreadBindingStatus()
+{
+ NativeThreadWrapper nativeThread;
+ nativeThread.setWaitForStop();
+
+ nativeThread.startAndWait();
+ QVERIFY(nativeThread.qthread);
+ auto privThread = static_cast<QThreadPrivate *>(QObjectPrivate::get(nativeThread.qthread));
+ QVERIFY(privThread->m_statusOrPendingObjects.bindingStatus());
+
+ nativeThread.stop();
+ nativeThread.join();
+}
+
// Disconnects on WinCE
void tst_QThread::stressTest()
{
@@ -1684,5 +1703,17 @@ void tst_QThread::threadIdReuse()
}
}
+void tst_QThread::bindingListCleanupAfterDelete()
+{
+ QThread t;
+ auto optr = std::make_unique<QObject>();
+ optr->moveToThread(&t);
+ auto threadPriv = static_cast<QThreadPrivate *>(QObjectPrivate::get(&t));
+ auto list = threadPriv->m_statusOrPendingObjects.list();
+ QVERIFY(list);
+ optr.reset();
+ QVERIFY(list->empty());
+}
+
QTEST_MAIN(tst_QThread)
#include "tst_qthread.moc"
diff --git a/tests/auto/corelib/tools/qmap/tst_qmap.cpp b/tests/auto/corelib/tools/qmap/tst_qmap.cpp
index e5bddb5d8d..2dd5db6e8a 100644
--- a/tests/auto/corelib/tools/qmap/tst_qmap.cpp
+++ b/tests/auto/corelib/tools/qmap/tst_qmap.cpp
@@ -447,7 +447,12 @@ void tst_QMap::beginEnd()
// detach
map2.insert( "2", "c" );
QVERIFY( map.constBegin() == map.constBegin() );
- QVERIFY( map.constBegin() != map2.constBegin() );
+
+ // comparing iterators between two different std::map is UB (and raises an
+ // assertion failure with MSVC debug-mode iterators), so we compare the
+ // elements' addresses.
+ QVERIFY(&map.constBegin().key() != &map2.constBegin().key());
+ QVERIFY(&map.constBegin().value() != &map2.constBegin().value());
}
void tst_QMap::firstLast()