summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/functions.cmake30
-rw-r--r--tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt6
-rw-r--r--tests/auto/corelib/global/qglobal/tst_qglobal.cpp13
-rw-r--r--tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp4
-rw-r--r--tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp63
-rw-r--r--tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp2
-rw-r--r--tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp29
-rw-r--r--tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp14
-rw-r--r--tests/auto/corelib/io/qsettings/tst_qsettings.cpp273
-rw-r--r--tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp23
-rw-r--r--tests/auto/corelib/kernel/qobject/tst_qobject.cpp6
-rw-r--r--tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp8
-rw-r--r--tests/auto/corelib/serialization/json/tst_qtjson.cpp22
-rw-r--r--tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp7
-rw-r--r--tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp61
-rw-r--r--tests/auto/corelib/thread/qfuture/tst_qfuture.cpp2
-rw-r--r--tests/auto/corelib/tools/qhash/tst_qhash.cpp2
-rw-r--r--tests/auto/corelib/tools/qlist/tst_qlist.cpp222
-rw-r--r--tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp8
-rw-r--r--tests/auto/gui/kernel/qwindow/tst_qwindow.cpp1
-rw-r--r--tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp26
-rw-r--r--tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp67
-rw-r--r--tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp79
-rw-r--r--tests/auto/other/qfocusevent/tst_qfocusevent.cpp2
-rw-r--r--tests/auto/testlib/initmain/tst_initmain.cpp3
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp63
-rw-r--r--tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp193
-rw-r--r--tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp95
-rw-r--r--tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp14
-rw-r--r--tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp49
30 files changed, 1062 insertions, 325 deletions
diff --git a/tests/auto/cmake/test_qt_add_ui_common/functions.cmake b/tests/auto/cmake/test_qt_add_ui_common/functions.cmake
index b06ba25e21f..d3878da3fbc 100644
--- a/tests/auto/cmake/test_qt_add_ui_common/functions.cmake
+++ b/tests/auto/cmake/test_qt_add_ui_common/functions.cmake
@@ -8,7 +8,30 @@ function(generate_hash_folder target_name infile out_folder)
set(${out_folder} "${short_hash}" PARENT_SCOPE)
endfunction()
+function(check_generator_works out_var generator_name)
+ message(STATUS "Checking if generator '${generator_name}' works")
+ string(CONCAT source_dir
+ "${CMAKE_CURRENT_SOURCE_DIR}/../"
+ "test_qt_add_ui_common/vs_generator_test")
+ set(build_dir
+ "${CMAKE_CURRENT_BINARY_DIR}/vs_generator_test-build")
+ run_cmake_configure(SOURCE_DIR "${source_dir}"
+ BUILD_DIR "${build_dir}"
+ GENERATOR "${generator_name}"
+ CLEAN_FIRST
+ RESULT_VARIABLE cmake_result)
+
+ if("${cmake_result}" EQUAL 0)
+ set(generator_works "TRUE")
+ else()
+ set(generator_works "FALSE")
+ endif()
+ message(STATUS "Checking if generator '${generator_name}' works - ${generator_works}")
+ set(${out_var} "${generator_works}" PARENT_SCOPE)
+endfunction()
+
function(get_latest_vs_generator output)
+ message(STATUS "Checking which latest Visual Studio generator can be used.")
execute_process(COMMAND ${CMAKE_COMMAND} -G
ERROR_VARIABLE CMAKE_GENERATORS_ERROR
OUTPUT_STRIP_TRAILING_WHITESPACE)
@@ -23,7 +46,14 @@ function(get_latest_vs_generator output)
set(last_generator "")
foreach(generator IN LISTS vs_generators)
string(REGEX MATCH "Visual Studio ([0-9]+) [0-9]+" unused "${generator}")
+
if("${CMAKE_MATCH_1}" VERSION_GREATER "${last_version}")
+ # Skip Visual Studio 18 2026 because it's not installed in CI yet
+ check_generator_works(generator_works "${CMAKE_MATCH_0}")
+ if(NOT generator_works)
+ continue()
+ endif()
+
set(last_version "${CMAKE_MATCH_1}")
set(last_generator "${CMAKE_MATCH_0}")
endif()
diff --git a/tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt b/tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt
new file mode 100644
index 00000000000..dbde5e369e5
--- /dev/null
+++ b/tests/auto/cmake/test_qt_add_ui_common/vs_generator_test/CMakeLists.txt
@@ -0,0 +1,6 @@
+# Copyright (C) 2025 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+
+project(VsGeneratorTest LANGUAGES CXX)
diff --git a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
index 3804f53cae9..0b65673c393 100644
--- a/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
+++ b/tests/auto/corelib/global/qglobal/tst_qglobal.cpp
@@ -92,6 +92,7 @@ private slots:
void qIsNull();
void for_each();
void qassert();
+ void qpresume();
void qtry();
void checkptr();
void qstaticassert();
@@ -266,6 +267,18 @@ void tst_QGlobal::qassert()
QVERIFY(passed);
}
+/*non-static*/ Q_NEVER_INLINE char presumedValue(const char *str)
+{
+ Q_PRESUME(str);
+ // an optimizing compiler should delete the str? check
+ return str ? str[0] : '\0';
+}
+
+void tst_QGlobal::qpresume()
+{
+ QCOMPARE(presumedValue("Hello World"), 'H');
+}
+
void tst_QGlobal::qtry()
{
int i = 0;
diff --git a/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
index ee50a311efa..185887e5d87 100644
--- a/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
+++ b/tests/auto/corelib/global/qxp/function_ref/tst_qxp_function_ref.cpp
@@ -54,6 +54,7 @@ void tst_qxp_function_ref::basics()
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
auto lambda = [](int i) noexcept { ++invoked; return i; };
const qxp::function_ref<int(int)> f = lambda;
QCOMPARE(invoked, 0);
@@ -85,6 +86,7 @@ void tst_qxp_function_ref::basics()
}
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
auto lambda = [] { ++invoked; return 42; };
const qxp::function_ref<int()> f = lambda;
QCOMPARE(invoked, 0);
@@ -106,6 +108,7 @@ void tst_qxp_function_ref::basics()
}
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
auto lambda = [] { ++invoked; };
const qxp::function_ref<void()> f = lambda;
QCOMPARE(invoked, 0);
@@ -157,6 +160,7 @@ void tst_qxp_function_ref::constOverloads()
void tst_qxp_function_ref::constExpr()
{
Q_CONSTINIT static int invoked = 0;
+ invoked = 0;
{
Q_CONSTINIT static auto lambda = [] (int i) { ++invoked; return i; };
// the function object constructor is constexpr, so this should be constinit:
diff --git a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
index 3a8ea31740c..29b78415924 100644
--- a/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
+++ b/tests/auto/corelib/io/qdirlisting/tst_qdirlisting.cpp
@@ -92,8 +92,8 @@ private slots:
void uncPaths();
#endif
#ifndef Q_OS_WIN
- void hiddenFiles();
- void hiddenDirs();
+ void hidden_data();
+ void hidden();
#endif
void withStdAlgorithms();
@@ -871,47 +871,46 @@ void tst_QDirListing::uncPaths()
// anything starting by a '.' is a hidden file.
// For that reason these two tests aren't run on Windows.
-void tst_QDirListing::hiddenFiles()
+void tst_QDirListing::hidden_data()
{
- QStringList expected = {
- "hiddenDirs_hiddenFiles/normalFile"_L1,
+ QTest::addColumn<QDirListing::IteratorFlags>("flags");
+ QTest::addColumn<QStringList>("expected");
+
+ using F = QDirListing::IteratorFlag;
+
+ QTest::newRow("Recursive-ExcludeDirs")
+ << (F::ExcludeDirs | F::IncludeHidden | F::Recursive)
+ << QStringList{
+ "hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile"_L1,
+ "hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile"_L1,
"hiddenDirs_hiddenFiles/.hiddenFile"_L1,
- "hiddenDirs_hiddenFiles/normalDirectory/normalFile"_L1,
"hiddenDirs_hiddenFiles/normalDirectory/.hiddenFile"_L1,
- "hiddenDirs_hiddenFiles/.hiddenDirectory/normalFile"_L1,
- "hiddenDirs_hiddenFiles/.hiddenDirectory/.hiddenFile"_L1,
- };
- expected.sort();
-
- constexpr auto flags = ItFlag::ExcludeDirs | ItFlag::IncludeHidden | ItFlag::Recursive;
- QStringList list;
- list.reserve(expected.size());
- for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, flags)) {
- QVERIFY(dirEntry.isFile());
- list.emplace_back(dirEntry.filePath());
- }
- list.sort();
+ "hiddenDirs_hiddenFiles/normalDirectory/normalFile"_L1,
+ "hiddenDirs_hiddenFiles/normalFile"_L1,
+ };
- QCOMPARE_EQ(list, expected);
+ QTest::newRow("Recursive-ExcludeFiles")
+ << (F::ExcludeFiles | F::IncludeHidden | F::Recursive)
+ << QStringList{
+ "hiddenDirs_hiddenFiles/.hiddenDirectory"_L1,
+ "hiddenDirs_hiddenFiles/.hiddenDirectory/.hidden-subdir"_L1,
+ "hiddenDirs_hiddenFiles/.hiddenDirectory/subdir"_L1,
+ "hiddenDirs_hiddenFiles/normalDirectory"_L1,
+ "hiddenDirs_hiddenFiles/normalDirectory/.hidden-subdir"_L1,
+ "hiddenDirs_hiddenFiles/normalDirectory/subdir"_L1,
+ };
}
-void tst_QDirListing::hiddenDirs()
+void tst_QDirListing::hidden()
{
- QStringList expected = {
- "hiddenDirs_hiddenFiles/normalDirectory"_L1,
- "hiddenDirs_hiddenFiles/normalDirectory/subdir"_L1,
- "hiddenDirs_hiddenFiles/normalDirectory/.hidden-subdir"_L1,
- "hiddenDirs_hiddenFiles/.hiddenDirectory"_L1,
- "hiddenDirs_hiddenFiles/.hiddenDirectory/subdir"_L1,
- "hiddenDirs_hiddenFiles/.hiddenDirectory/.hidden-subdir"_L1,
- };
- expected.sort();
+ QFETCH(QDirListing::IteratorFlags, flags);
+ QFETCH(QStringList, expected);
- constexpr auto flags = ItFlag::ExcludeFiles | ItFlag::IncludeHidden | ItFlag::Recursive;
QStringList list;
list.reserve(expected.size());
+ bool isDir = flags.testFlags(ItFlag::ExcludeFiles);
for (const auto &dirEntry : QDirListing(u"hiddenDirs_hiddenFiles"_s, flags)) {
- QVERIFY(dirEntry.isDir());
+ QVERIFY(isDir ? dirEntry.isDir() : dirEntry.isFile());
list.emplace_back(dirEntry.filePath());
}
list.sort();
diff --git a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
index 560d4196b28..6a898e7af0d 100644
--- a/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
+++ b/tests/auto/corelib/io/qprocessenvironment/tst_qprocessenvironment.cpp
@@ -291,7 +291,7 @@ void tst_QProcessEnvironment::putenv()
static bool testRan = false;
if (testRan)
- QFAIL("You cannot run this test more than once, since we modify the environment");
+ QSKIP("You cannot run this test more than once, since we modify the environment");
testRan = true;
QByteArray valBefore = qgetenv(envname);
diff --git a/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp b/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp
index 4fb54581a6d..6dceb583469 100644
--- a/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp
+++ b/tests/auto/corelib/io/qrandomaccessasyncfile/tst_qrandomaccessasyncfile.cpp
@@ -464,7 +464,12 @@ void tst_QRandomAccessAsyncFile::errorHandling_data()
<< qint64(0) << QIOOperation::Error::FileNotOpen;
QTest::newRow("read_writeonly")
<< QIOOperation::Type::Read << QIODeviceBase::WriteOnly
- << qint64(0) << QIOOperation::Error::Read;
+ << qint64(0)
+#ifdef Q_OS_DARWIN
+ << QIOOperation::Error::FileNotOpen;
+#else
+ << QIOOperation::Error::Read;
+#endif
QTest::newRow("read_negative_offset")
<< QIOOperation::Type::Read << QIODeviceBase::ReadOnly
<< qint64(-1) << QIOOperation::Error::IncorrectOffset;
@@ -478,7 +483,12 @@ void tst_QRandomAccessAsyncFile::errorHandling_data()
<< qint64(0) << QIOOperation::Error::FileNotOpen;
QTest::newRow("write_readonly")
<< QIOOperation::Type::Write << QIODeviceBase::ReadOnly
- << qint64(0) << QIOOperation::Error::Write;
+ << qint64(0)
+#ifdef Q_OS_DARWIN
+ << QIOOperation::Error::FileNotOpen;
+#else
+ << QIOOperation::Error::Write;
+#endif
QTest::newRow("write_negative_offset")
<< QIOOperation::Type::Write << QIODeviceBase::WriteOnly
<< qint64(-1) << QIOOperation::Error::IncorrectOffset;
@@ -545,8 +555,9 @@ void tst_QRandomAccessAsyncFile::fileClosedInProgress()
}
constexpr qint64 OneMb = 1024 * 1024;
- std::array<QIOOperation *, 5> operations;
- std::array<QByteArray, 5> buffers;
+ constexpr size_t NumOps = 5;
+ std::array<QIOOperation *, NumOps> operations;
+ std::array<QByteArray, NumOps> buffers;
for (size_t i = 0; i < operations.size(); ++i) {
const qint64 offset = i * OneMb;
@@ -596,8 +607,9 @@ void tst_QRandomAccessAsyncFile::fileRemovedInProgress()
QFETCH(const QIOOperation::Type, operation);
constexpr qint64 OneMb = 1024 * 1024;
- std::array<QIOOperation *, 5> operations;
- std::array<QByteArray, 5> buffers;
+ constexpr size_t NumOps = 5;
+ std::array<QIOOperation *, NumOps> operations;
+ std::array<QByteArray, NumOps> buffers;
{
QRandomAccessAsyncFile file;
@@ -655,8 +667,9 @@ void tst_QRandomAccessAsyncFile::operationsDeletedInProgress()
}
constexpr qint64 OneMb = 1024 * 1024;
- std::array<QIOOperation *, 5> operations;
- std::array<QByteArray, 5> buffers;
+ constexpr size_t NumOps = 5;
+ std::array<QIOOperation *, NumOps> operations;
+ std::array<QByteArray, NumOps> buffers;
for (size_t i = 0; i < operations.size(); ++i) {
const qint64 offset = i * OneMb;
diff --git a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
index 472e03adcac..00672ef0b6a 100644
--- a/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
+++ b/tests/auto/corelib/io/qresourceengine/tst_qresourceengine.cpp
@@ -678,8 +678,20 @@ void tst_QResourceEngine::registerNestedRccFile()
"/registeredNestedRccFile"));
QVERIFY2(QResource::registerResource(":/nestedrcc/runtime_resource.rcc",
"/registeredNestedRccFile"),
- "Second QResource::registerResource call failed.");
+ "Second QResource::registerResource call does not failed.");
QVERIFY(QFile::exists(":/registeredNestedRccFile/runtime_resource/search_file.txt"));
+
+ // clean up
+ QVERIFY(QResource::unregisterResource(":/nestedrcc/runtime_resource.rcc",
+ "/registeredNestedRccFile"));
+
+ QVERIFY(QFile::exists(":/registeredNestedRccFile/runtime_resource/search_file.txt"));
+
+ QVERIFY(QResource::unregisterResource(":/nestedrcc/runtime_resource.rcc",
+ "/registeredNestedRccFile"));
+
+ // verify clean up
+ QVERIFY(!QFile::exists(":/registeredNestedRccFile/runtime_resource/search_file.txt"));
}
QTEST_MAIN(tst_QResourceEngine)
diff --git a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
index 3dd36bdae35..5453237cadb 100644
--- a/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
+++ b/tests/auto/corelib/io/qsettings/tst_qsettings.cpp
@@ -182,7 +182,16 @@ private slots:
void childKeys();
void testIniParsing_data();
void testIniParsing();
+
void testEscapes();
+ void testEscapedKeys_data();
+ void testEscapedKeys();
+ void testUnescapedKeys_data();
+ void testUnescapedKeys();
+ void testEscapedStringList_data();
+ void testEscapedStringList();
+ void testUnescapedStringList_data();
+ void testUnescapedStringList();
void testNormalizedKey_data();
void testNormalizedKey();
void testVariantTypes_data() { populateWithFormats(); }
@@ -2831,35 +2840,6 @@ void tst_QSettings::testEscapes()
{
QSettings settings(QSettings::UserScope, "software.org", "KillerAPP");
-#define testEscapedKey(plainKey, escKey) \
- QCOMPARE(iniEscapedKey(plainKey), QByteArray(escKey)); \
- QCOMPARE(iniUnescapedKey(escKey), QString(plainKey));
-
-#define testUnescapedKey(escKey, plainKey, reescKey) \
- QCOMPARE(iniUnescapedKey(escKey), QString(plainKey)); \
- QCOMPARE(iniEscapedKey(plainKey), QByteArray(reescKey)); \
- QCOMPARE(iniUnescapedKey(reescKey), QString(plainKey));
-
-#define testEscapedStringList(plainStrList, escStrList) \
- { \
- QStringList plainList(plainStrList); \
- QByteArray escList(escStrList); \
- QCOMPARE(iniEscapedStringList(plainList), escList); \
- QCOMPARE(iniUnescapedStringList(escList), plainList); \
- } \
-
-
-#define testUnescapedStringList(escStrList, plainStrList, reescStrList) \
- { \
- QStringList plainList(plainStrList); \
- QByteArray escList(escStrList); \
- QByteArray reescList(reescStrList); \
- QCOMPARE(iniUnescapedStringList(escList), plainList); \
- QCOMPARE(iniEscapedStringList(plainList), reescList); \
- QCOMPARE(iniUnescapedStringList(reescList), plainList); \
- } \
-
-
#define testVariant(val, escStr, func) \
{ \
QVariant v(val); \
@@ -2875,57 +2855,6 @@ void tst_QSettings::testEscapes()
QCOMPARE(v.toString(), QString(vStr)); \
}
- testEscapedKey("", "");
- testEscapedKey(" ", "%20");
- testEscapedKey(" 0123 abcd ", "%200123%20abcd%20");
- testEscapedKey("~!@#$%^&*()_+.-/\\=", "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D");
- testEscapedKey(QString() + QChar(0xabcd) + QChar(0x1234) + QChar(0x0081), "%UABCD%U1234%81");
- testEscapedKey(QString() + QChar(0xFE) + QChar(0xFF) + QChar(0x100) + QChar(0x101), "%FE%FF%U0100%U0101");
-
- testUnescapedKey("", "", "");
- testUnescapedKey("%20", " ", "%20");
- testUnescapedKey("/alpha/beta", "/alpha/beta", "\\alpha\\beta");
- testUnescapedKey("\\alpha\\beta", "/alpha/beta", "\\alpha\\beta");
- testUnescapedKey("%5Calpha%5Cbeta", "\\alpha\\beta", "%5Calpha%5Cbeta");
- testUnescapedKey("%", "%", "%25");
- testUnescapedKey("%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%", QString("%f%!%%%%1x%x1%U%Uz%U123") + QChar(0x1234) + "\x12" + "34%",
- "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25");
-
- testEscapedStringList("", "");
- testEscapedStringList(" ", "\" \"");
- testEscapedStringList(";", "\";\"");
- testEscapedStringList(",", "\",\"");
- testEscapedStringList("=", "\"=\"");
- testEscapedStringList("abc-def", "abc-def");
- testEscapedStringList(QChar(0) + QString("0"), "\\0\\x30");
- testEscapedStringList("~!@#$%^&*()_+.-/\\=", "\"~!@#$%^&*()_+.-/\\\\=\"");
- testEscapedStringList("~!@#$%^&*()_+.-/\\", "~!@#$%^&*()_+.-/\\\\");
- testEscapedStringList(QString("\x7F") + "12aFz", QByteArray("\x7f") + "12aFz");
- testEscapedStringList(QString(" \t\n\\n") + QChar(0x123) + QChar(0x4567), "\" \\t\\n\\\\n\xC4\xA3\xE4\x95\xA7\"");
- testEscapedStringList(QString("\a\b\f\n\r\t\v'\"?\001\002\x03\x04"), "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4");
- testEscapedStringList(QStringList() << "," << ";" << "a" << "ab, \tc, d ", "\",\", \";\", a, \"ab, \\tc, d \"");
-
- /*
- Test .ini syntax that cannot be generated by QSettings (but can be entered by users).
- */
- testUnescapedStringList("", "", "");
- testUnescapedStringList("\"\"", "", "");
- testUnescapedStringList("\"abcdef\"", "abcdef", "abcdef");
- testUnescapedStringList("\"\\?\\'\\\"\"", "?'\"", "?'\\\"");
- testUnescapedStringList("\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\",
- QString() + QChar(0) + QChar(0) + QChar(0) + QChar(0) + QChar(1)
- + QChar(0111) + QChar(011111) + QChar(0) + QChar(0xCDEF) + "GH"
- + QChar(0x3456),
- "\\0\\0\\0\\0\\x1I\xE1\x89\x89\\0\xEC\xB7\xAFGH\xE3\x91\x96");
- testUnescapedStringList(QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16), "\f", "\\f");
- testUnescapedStringList("\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,",
- QStringList() << "a" << "bc " << " d" << "ef " << "" << "g" << "hi i"
- << "" << "" << "" << "",
- "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , ");
- testUnescapedStringList("a , b , c d , efg ",
- QStringList() << "a" << "b" << "c d" << "efg",
- "a, b, c d, efg");
-
// streaming qvariant into a string
testVariant(QString("Hello World!"), QString("Hello World!"), toString);
testVariant(QString("Hello, World!"), QString("Hello, World!"), toString);
@@ -2949,6 +2878,190 @@ void tst_QSettings::testEscapes()
testBadEscape("@Rect(1 2 3)", "@Rect(1 2 3)");
testBadEscape("@@Rect(1 2 3)", "@Rect(1 2 3)");
}
+
+void tst_QSettings::testEscapedKeys_data()
+{
+ QTest::addColumn<QString>("plainKey");
+ QTest::addColumn<QByteArray>("escKey");
+
+ QTest::newRow("empty-string") << u""_s << ""_ba;
+ QTest::newRow("space") << u" "_s << "%20"_ba;
+ QTest::newRow(" 0123 abcd ") << " 0123 abcd " << "%200123%20abcd%20"_ba;
+
+ QTest::newRow("special-characters")
+ << "~!@#$%^&*()_+.-/\\="
+ << "%7E%21%40%23%24%25%5E%26%2A%28%29_%2B.-\\%5C%3D"_ba;
+
+ const std::array arr1 = {QChar(0xabcd), QChar(0x1234), QChar(0x0081)};
+ QTest::newRow("qchar-array1") << QString(arr1) << "%UABCD%U1234%81"_ba;
+
+ const std::array arr2 = {QChar(0xFE), QChar(0xFF), QChar(0x100), QChar(0x101)};
+ QTest::newRow("qchar-array2") << QString(arr2) << "%FE%FF%U0100%U0101"_ba;
+}
+
+void tst_QSettings::testEscapedKeys()
+{
+ QFETCH(QString, plainKey);
+ QFETCH(QByteArray, escKey);
+
+ QSettings settings(QSettings::UserScope, "example.org", "KillerAPP");
+
+ QCOMPARE(iniEscapedKey(plainKey), escKey);
+ QCOMPARE(iniUnescapedKey(escKey), plainKey);
+}
+
+void tst_QSettings::testUnescapedKeys_data()
+{
+ QTest::addColumn<QByteArray>("escKey");
+ QTest::addColumn<QString>("plainKey");
+ QTest::addColumn<QByteArray>("reescKey");
+
+ QTest::newRow("empty-string") << ""_ba << u""_s << ""_ba;
+ QTest::newRow("space") << "%20"_ba << u" "_s << "%20"_ba;
+ QTest::newRow("%") << "%"_ba << u"%"_s << "%25"_ba;
+
+ QTest::newRow("/alpha/beta") << "/alpha/beta"_ba << "/alpha/beta" << "\\alpha\\beta"_ba;
+ QTest::newRow("\\alpha\\beta") << "\\alpha\\beta"_ba << "/alpha/beta" << "\\alpha\\beta"_ba;
+ QTest::newRow("%5Calpha%5Cbeta") << "%5Calpha%5Cbeta"_ba << "\\alpha\\beta" << "%5Calpha%5Cbeta"_ba;
+
+ QTest::newRow("many-percent")
+ << "%f%!%%%%1x%x1%U%Uz%U123%U1234%1234%"_ba
+ << QString("%f%!%%%%1x%x1%U%Uz%U123"_L1 + QChar(0x1234) + "\x12" + "34%")
+ << "%25f%25%21%25%25%25%251x%25x1%25U%25Uz%25U123%U1234%1234%25"_ba;
+}
+
+void tst_QSettings::testUnescapedKeys()
+{
+ QFETCH(QByteArray, escKey);
+ QFETCH(QString, plainKey);
+ QFETCH(QByteArray, reescKey);
+
+ QSettings settings(QSettings::UserScope, "example.org", "KillerAPP");
+
+ QCOMPARE(iniUnescapedKey(escKey), plainKey);
+ QCOMPARE(iniEscapedKey(plainKey), reescKey);
+ QCOMPARE(iniUnescapedKey(reescKey), plainKey);
+}
+
+void tst_QSettings::testEscapedStringList_data()
+{
+ QTest::addColumn<QStringList>("plainStrList");
+ QTest::addColumn<QByteArray>("escapedList");
+
+ QTest::newRow("empty-string") << QStringList{u""_s} << ""_ba;
+ QTest::newRow("space") << QStringList{u" "_s} << "\" \""_ba;
+ QTest::newRow(";") << QStringList{u";"_s} << "\";\""_ba;
+ QTest::newRow(",") << QStringList{u","_s} << "\",\""_ba;
+ QTest::newRow("=") << QStringList{u"="_s} << "\"=\""_ba;
+ QTest::newRow("abc-def") << QStringList{u"abc-def"_s} << "abc-def"_ba;
+
+ QTest::newRow("starts-with-NUL")
+ << QStringList{QChar(0) + u"0"_s}
+ << "\\0\\x30"_ba;
+
+ QTest::newRow("special-characters1")
+ << QStringList{u"~!@#$%^&*()_+.-/\\="_s}
+ << "\"~!@#$%^&*()_+.-/\\\\=\""_ba;
+
+ QTest::newRow("special-characters2")
+ << QStringList{u"~!@#$%^&*()_+.-/\\"_s}
+ << "~!@#$%^&*()_+.-/\\\\"_ba;
+
+ QTest::newRow("DEL-character")
+ << QStringList{u"\x7F"_s + u"12aFz"_s}
+ << "\x7f"_ba + "12aFz"_ba;
+
+ QTest::newRow("tab-newline")
+ << QStringList{u" \t\n\\n"_s + QChar(0x123) + QChar(0x4567)}
+ << "\" \\t\\n\\\\n\xC4\xA3\xE4\x95\xA7\""_ba;
+
+ QTest::newRow("backslash-espcaped-input")
+ << QStringList{u"\a\b\f\n\r\t\v'\"?\001\002\x03\x04"_s}
+ << "\\a\\b\\f\\n\\r\\t\\v'\\\"?\\x1\\x2\\x3\\x4"_ba;
+
+ QTest::newRow("stringlist-with-tab")
+ << QStringList{u","_s, u";"_s, u"a"_s, u"ab, \tc, d "_s}
+ << "\",\", \";\", a, \"ab, \\tc, d \""_ba;
+}
+
+void tst_QSettings::testEscapedStringList()
+{
+ QFETCH(QStringList, plainStrList);
+ QFETCH(QByteArray, escapedList);
+
+ QSettings settings(QSettings::UserScope, "example.org", "KillerAPP");
+
+ QCOMPARE(iniEscapedStringList(plainStrList), escapedList);
+ QCOMPARE(iniUnescapedStringList(escapedList), plainStrList);
+}
+
+void tst_QSettings::testUnescapedStringList_data()
+{
+ QTest::addColumn<QByteArray>("escStrList");
+ QTest::addColumn<QStringList>("plainStrList");
+ QTest::addColumn<QByteArray>("reescStrList");
+
+ /*
+ Test .ini syntax that cannot be generated by QSettings (but can be entered by users).
+ */
+ QTest::newRow("empty")
+ << ""_ba
+ << QStringList{u""_s}
+ << ""_ba;
+
+ QTest::newRow("empty-double-quotes")
+ << "\"\""_ba
+ << QStringList{u""_s}
+ << ""_ba;
+
+ QTest::newRow("plain-quoted-string")
+ << "\"abcdef\""_ba
+ << QStringList{u"abcdef"_s}
+ << "abcdef"_ba;
+
+ QTest::newRow("backslash-non-letter-characters")
+ << "\"\\?\\'\\\"\""_ba
+ << QStringList{u"?'\""_s}
+ << "?'\\\""_ba;
+
+ const std::array arr = {QChar(0), QChar(0), QChar(0), QChar(0), QChar(1),
+ QChar(0111), QChar(011111), QChar(0), QChar(0xCDEF),
+ QChar(u'G'), QChar(u'H'), QChar(0x3456)};
+ QTest::newRow("array-of-qchar")
+ << "\\0\\00\\000\\0000000\\1\\111\\11111\\x\\x0\\xABCDEFGH\\x0123456\\"_ba
+ << QStringList{QString{arr}}
+ << "\\0\\0\\0\\0\\x1I\xE1\x89\x89\\0\xEC\xB7\xAFGH\xE3\x91\x96"_ba;
+
+ QTest::newRow("backslash-escapes")
+ << QByteArray("\\c\\d\\e\\f\\g\\$\\*\\\0", 16)
+ << QStringList{u"\f"_s}
+ << "\\f"_ba;
+
+ QTest::newRow("double-quotes-tab-character")
+ << "\"a\", \t\"bc \", \" d\" , \"ef \" ,,g, hi i,,, ,"_ba
+ << QStringList{u"a"_s, u"bc "_s, u" d"_s, u"ef "_s, u""_s, u"g"_s,
+ u"hi i"_s, u""_s, u""_s, u""_s, u""_s}
+ << "a, \"bc \", \" d\", \"ef \", , g, hi i, , , , "_ba;
+
+ QTest::newRow("abcdefg-extra-whitespaces")
+ << "a , b , c d , efg "_ba
+ << QStringList{u"a"_s, u"b"_s, u"c d"_s, u"efg"_s}
+ << "a, b, c d, efg"_ba;
+}
+
+void tst_QSettings::testUnescapedStringList()
+{
+ QFETCH(QByteArray, escStrList);
+ QFETCH(QStringList, plainStrList);
+ QFETCH(QByteArray, reescStrList);
+
+ QSettings settings(QSettings::UserScope, "example.org", "KillerAPP");
+
+ QCOMPARE(iniUnescapedStringList(escStrList), plainStrList);
+ QCOMPARE(iniEscapedStringList(plainStrList), reescStrList);
+ QCOMPARE(iniUnescapedStringList(reescStrList), plainStrList);
+}
+
#endif
void tst_QSettings::testCaseSensitivity()
diff --git a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
index 7c0e5e10b71..bb7555f0329 100644
--- a/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
+++ b/tests/auto/corelib/kernel/qmetaobjectbuilder/tst_qmetaobjectbuilder.cpp
@@ -22,6 +22,7 @@ private slots:
void variantProperty();
void notifySignal();
void enumerator();
+ void enumProperty();
void classInfo();
void relatedMetaObject();
void staticMetacall();
@@ -1019,6 +1020,26 @@ void tst_QMetaObjectBuilder::enumerator()
QVERIFY(checkForSideEffects(builder, QMetaObjectBuilder::Enumerators));
}
+void tst_QMetaObjectBuilder::enumProperty()
+{
+ // When adding property with an enumeration type, QMetaProperty::isEnumType()
+ // should return true.
+ QMetaObjectBuilder builder;
+ builder.setSuperClass(QObject::metaObject());
+
+ auto enumMetaType = QMetaType::fromType<Qt::Orientation>();
+ QVERIFY(enumMetaType.isValid());
+
+ builder.addProperty("orientation", "Qt::Orientation", enumMetaType);
+
+ auto *mo = builder.toMetaObject();
+ QVERIFY(mo != nullptr);
+ const int index = mo->indexOfProperty("orientation");
+ QVERIFY(index != -1);
+ QVERIFY(mo->property(index).isEnumType());
+ free(mo);
+}
+
void tst_QMetaObjectBuilder::classInfo()
{
QMetaObjectBuilder builder;
@@ -1711,7 +1732,7 @@ void tst_QMetaObjectBuilder::usage_templateConnect()
testObject.data(), &TestObject::voidSlotInt));
// Something that isn't a signal
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in TestObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(TestObject, TestObject): signal not found");
con = QObject::connect(testObject.data(), &TestObject::setIntProp,
testObject.data(), &TestObject::intPropChanged);
QVERIFY(!con);
diff --git a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
index 220d3af568b..afb0bf0169a 100644
--- a/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
+++ b/tests/auto/corelib/kernel/qobject/tst_qobject.cpp
@@ -4864,18 +4864,18 @@ void tst_QObject::pointerConnect()
QVERIFY(!QObject::disconnect(con));
//connect a slot to a signal (== error)
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(ReceiverObject, SenderObject): signal not found");
con = connect(&r1, &ReceiverObject::slot4 , &s, &SenderObject::signal4);
QVERIFY(!con);
QVERIFY(!QObject::disconnect(con));
//connect an arbitrary PMF to a slot
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(ReceiverObject, ReceiverObject): signal not found");
con = connect(&r1, &ReceiverObject::reset, &r1, &ReceiverObject::slot1);
QVERIFY(!con);
QVERIFY(!QObject::disconnect(con));
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in ReceiverObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(ReceiverObject, ReceiverObject): signal not found");
con = connect(&r1, &ReceiverObject::reset, &r1, [](){});
QVERIFY(!con);
QVERIFY(!QObject::disconnect(con));
diff --git a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
index adff512e6a3..81316b061d0 100644
--- a/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
+++ b/tests/auto/corelib/kernel/qtimer/tst_qtimer.cpp
@@ -45,11 +45,11 @@ using namespace std::chrono_literals;
class tst_QTimer : public QObject
{
Q_OBJECT
-public:
- static void initMain();
private slots:
+ void initTestCase();
void cleanupTestCase();
+
void zeroTimer();
void singleShotTimeout();
void timeout();
@@ -1678,11 +1678,11 @@ struct StaticSingleShotUser
};
// NOTE: to prevent any static initialization order fiasco, we implement
-// initMain() to instantiate staticSingleShotUser before qApp
+// initTestCase() to instantiate staticSingleShotUser before qApp
static StaticSingleShotUser *s_staticSingleShotUser = nullptr;
-void tst_QTimer::initMain()
+void tst_QTimer::initTestCase()
{
s_staticSingleShotUser = new StaticSingleShotUser;
}
diff --git a/tests/auto/corelib/serialization/json/tst_qtjson.cpp b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
index 2e0d8dd7be2..dbaf6873af2 100644
--- a/tests/auto/corelib/serialization/json/tst_qtjson.cpp
+++ b/tests/auto/corelib/serialization/json/tst_qtjson.cpp
@@ -3595,7 +3595,7 @@ void tst_QtJson::bom()
QCOMPARE(error.error, QJsonParseError::NoError);
}
-void tst_QtJson::nesting()
+static void nesting_test()
{
// check that we abort parsing too deeply nested json documents.
// this is to make sure we don't crash because the parser exhausts the
@@ -3654,6 +3654,26 @@ void tst_QtJson::nesting()
}
+void tst_QtJson::nesting()
+{
+#if defined(Q_OS_QNX) || defined(Q_OS_VXWORKS) || defined(Q_OS_WASM)
+ // This test misbehaving probably indicates a stack overflow due to the
+ // recursive parser in qjsonparser.cpp. The recursion prevention limit may
+ // be too high for this platform. Someone should investigate.
+ QSKIP("Test freezes or crashes - probably a stack overflow");
+#endif
+
+ QThread *thr = QThread::create(nesting_test);
+#if defined(__SANITIZE_ADDRESS__) || __has_feature(address_sanitizer) || \
+ defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)
+ // force a larger stack size - 8 MB seems sufficient
+ thr->setStackSize(8192 * 1024);
+#endif
+ thr->start();
+ thr->wait();
+ delete thr;
+}
+
void tst_QtJson::longStrings()
{
// test around 15 and 16 bit boundaries, as these are limits
diff --git a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
index e0173412339..a6662878786 100644
--- a/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
+++ b/tests/auto/corelib/text/qbytearray/tst_qbytearray.cpp
@@ -2484,6 +2484,10 @@ void tst_QByteArray::fromPercentEncoding()
QFETCH(QByteArray, decodedString);
QCOMPARE(encodedString.percentDecoded(), decodedString);
+ QCOMPARE(QByteArray::fromPercentEncoding(encodedString), decodedString);
+ QCOMPARE(QByteArray{encodedString}.percentDecoded(), decodedString); // rvalue, shared
+ encodedString.detach();
+ QCOMPARE(std::move(encodedString).percentDecoded(), decodedString); // rvalue, detached
}
void tst_QByteArray::toPercentEncoding_data()
@@ -2545,6 +2549,9 @@ void tst_QByteArray::pecentEncodingRoundTrip()
QByteArray encodedData = original.toPercentEncoding(excludeInEncoding, includeInEncoding);
QCOMPARE(encodedData, encoded);
QCOMPARE(encodedData.percentDecoded(), original);
+ QCOMPARE(QByteArray{encodedData}.percentDecoded(), original); // rvalue, shared
+ encodedData.detach();
+ QCOMPARE(std::move(encodedData).percentDecoded(), original); // rvalue, detached
}
struct StringComparisonData
diff --git a/tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp b/tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp
index 22bff24eec0..c0a67840c75 100644
--- a/tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp
+++ b/tests/auto/corelib/text/qstringiterator/tst_qstringiterator.cpp
@@ -11,6 +11,8 @@ class tst_QStringIterator : public QObject
private slots:
void sweep_data();
void sweep();
+ void nextOrRawCodeUnitEquivalenceWithOldCode_data() { sweep_data(); }
+ void nextOrRawCodeUnitEquivalenceWithOldCode();
void position();
};
@@ -253,6 +255,65 @@ void tst_QStringIterator::sweep()
}
}
+void tst_QStringIterator::nextOrRawCodeUnitEquivalenceWithOldCode()
+{
+ QFETCH(const QString, string);
+ // QFETCH(bool, valid);
+
+ const auto s = string.data_ptr().data(); // avoids QChar
+
+ // this is the old code, used before we had nextOrRawCodeUnit():
+ const auto oldResult = [&] {
+ QList<char32_t> result;
+ result.reserve(string.size());
+
+ const auto len = string.size();
+ for (qsizetype i = 0; i < len; ++i) {
+ QT_WARNING_PUSH
+ QT_WARNING_DISABLE_CLANG("-Wcharacter-conversion")
+ char32_t ucs4;
+ const char16_t c = s[i];
+ if (QChar::isHighSurrogate(c) && i + 1 < len && QChar::isLowSurrogate(s[i + 1]))
+ ucs4 = QChar::surrogateToUcs4(c, s[++i]);
+ else
+ ucs4 = c;
+ QT_WARNING_POP
+ result.push_back(ucs4);
+ }
+ return result;
+ }();
+
+ // now the same with nextOrRawCodeUnit():
+ const auto newResult = [&] {
+ QList<char32_t> result;
+ result.reserve(string.size());
+
+ QStringIterator it(string);
+ while (it.hasNext())
+ result.push_back(it.nextOrRawCodeUnit());
+
+ return result;
+ }();
+
+ // they should yield the equivalent series of code points:
+ QCOMPARE_EQ(newResult, oldResult);
+
+ // also check next/previousOrRawCodeUnit() consistency:
+ const auto fromBack = [&] {
+ QList<char32_t> result;
+ result.reserve(string.size());
+
+ QStringIterator it(string, string.size());
+ while (it.hasPrevious())
+ result.push_back(it.previousOrRawCodeUnit());
+
+ std::reverse(result.begin(), result.end());
+ return result;
+ }();
+
+ QCOMPARE_EQ(fromBack, newResult);
+}
+
void tst_QStringIterator::position()
{
static const QChar stringData[] =
diff --git a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
index 76fcee11b7b..806b6b43161 100644
--- a/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
+++ b/tests/auto/corelib/thread/qfuture/tst_qfuture.cpp
@@ -3998,7 +3998,7 @@ void tst_QFuture::signalConnect()
#if defined(Q_CC_MSVC_ONLY) && (Q_CC_MSVC < 1940 || !defined(_DEBUG))
#define EXPECT_FUTURE_CONNECT_FAIL() QEXPECT_FAIL("", "QTBUG-101761, test fails on Windows/MSVC", Continue)
#else
- QTest::ignoreMessage(QtWarningMsg, "QObject::connect: signal not found in SenderObject");
+ QTest::ignoreMessage(QtWarningMsg, "QObject::connect(SenderObject, SenderObject): signal not found");
#define EXPECT_FUTURE_CONNECT_FAIL()
#endif
diff --git a/tests/auto/corelib/tools/qhash/tst_qhash.cpp b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
index b03750389bd..8ec9cb516d3 100644
--- a/tests/auto/corelib/tools/qhash/tst_qhash.cpp
+++ b/tests/auto/corelib/tools/qhash/tst_qhash.cpp
@@ -3153,6 +3153,8 @@ qHash(const StdHashKeyType<HasQHash> &s, size_t seed)
template <typename T>
void stdHashImpl()
{
+ T::StdHashUsed = false;
+
QHash<T, int> hash;
for (int i = 0; i < 1000; ++i)
hash.insert(T{i}, i);
diff --git a/tests/auto/corelib/tools/qlist/tst_qlist.cpp b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
index e84c35691da..a19cebe3faf 100644
--- a/tests/auto/corelib/tools/qlist/tst_qlist.cpp
+++ b/tests/auto/corelib/tools/qlist/tst_qlist.cpp
@@ -121,6 +121,84 @@ Q_DECLARE_TYPEINFO(Movable, Q_RELOCATABLE_TYPE);
QT_END_NAMESPACE
Q_DECLARE_METATYPE(Movable);
+struct NoexceptMovable
+{
+ NoexceptMovable(char input = 'j') noexcept
+ : i(input)
+ {
+ counter.fetchAndAddRelaxed(1);
+ }
+ NoexceptMovable(const NoexceptMovable &other) noexcept
+ : i(other.i)
+ {
+ check(other.state, Constructed);
+ counter.fetchAndAddRelaxed(1);
+ }
+ NoexceptMovable(NoexceptMovable &&other) noexcept
+ : i(other.i)
+ {
+ check(other.state, Constructed);
+ counter.fetchAndAddRelaxed(1);
+ other.that = nullptr;
+ }
+
+ ~NoexceptMovable() // implicitly noexcept
+ {
+ check(state, Constructed);
+ i = 0;
+ counter.fetchAndAddRelaxed(-1);
+ state = Destructed; // this is likely a dead store
+ }
+
+ bool operator ==(const NoexceptMovable &other) const noexcept
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ return i == other.i;
+ }
+
+ NoexceptMovable &operator=(const NoexceptMovable &other) noexcept
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ that = this;
+ return *this;
+ }
+ NoexceptMovable &operator=(NoexceptMovable &&other) noexcept
+ {
+ check(state, Constructed);
+ check(other.state, Constructed);
+ i = other.i;
+ that = other.that;
+ other.that = nullptr;
+ return *this;
+ }
+ bool wasConstructedAt(const NoexceptMovable *other) const noexcept
+ {
+ return that == other;
+ }
+ char i;
+ static inline QAtomicInt counter;
+private:
+ NoexceptMovable *that = this; // used to check if an instance was moved
+
+ enum State { Constructed = 106, Destructed = 110 };
+ State state = Constructed;
+
+ static void check(const State state1, const State state2) noexcept
+ {
+ QCOMPARE(state1, state2);
+ }
+
+ friend inline size_t qHash(const NoexceptMovable &key, size_t seed) noexcept
+ { return qHash(key.i, seed); }
+};
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(NoexceptMovable, Q_RELOCATABLE_TYPE);
+QT_END_NAMESPACE
+
struct Custom {
Custom(char input = 'j')
: i(input)
@@ -225,37 +303,47 @@ private slots:
void constructors_reserveAndInitialize() const;
void copyConstructorInt() const { copyConstructor<int>(); }
void copyConstructorMovable() const { copyConstructor<Movable>(); }
+ void copyConstructorNoexceptMovable() const { copyConstructor<NoexceptMovable>(); }
void copyConstructorCustom() const { copyConstructor<Custom>(); }
void assignmentInt() const { testAssignment<int>(); }
void assignmentMovable() const { testAssignment<Movable>(); }
+ void assignmentNoexceptMovable() const { testAssignment<NoexceptMovable>(); }
void assignmentCustom() const { testAssignment<Custom>(); }
void assignFromInitializerListInt() const { assignFromInitializerList<int>(); }
void assignFromInitializerListMovable() const { assignFromInitializerList<Movable>(); }
+ void assignFromInitializerListNoexceptMovable() const { assignFromInitializerList<NoexceptMovable>(); }
void assignFromInitializerListCustom() const { assignFromInitializerList<Custom>(); }
void addInt() const { add<int>(); }
void addMovable() const { add<Movable>(); }
+ void addNoexceptMovable() const { add<NoexceptMovable>(); }
void addCustom() const { add<Custom>(); }
void appendInt() const { append<int>(); }
void appendMovable() const { append<Movable>(); }
+ void appendNoexceptMovable() const { append<NoexceptMovable>(); }
void appendCustom() const { append<Custom>(); }
void appendRvalue() const;
void appendList() const;
void assignEmpty() const;
void assignInt() const { assign<int>(); }
void assignMovable() const { assign<Movable>(); }
+ void assignNoexceptMovable() const { assign<NoexceptMovable>(); }
void assignCustom() const { assign<Custom>(); }
void assignUsesPrependBuffer_int_data() { assignUsesPrependBuffer_data(); }
void assignUsesPrependBuffer_int() const { assignUsesPrependBuffer<int>(); }
void assignUsesPrependBuffer_Movable_data() { assignUsesPrependBuffer_data(); }
void assignUsesPrependBuffer_Movable() const { assignUsesPrependBuffer<Movable>(); }
+ void assignUsesPrependBuffer_NoexceptMovable_data() { assignUsesPrependBuffer_data(); }
+ void assignUsesPrependBuffer_NoexceptMovable() const { assignUsesPrependBuffer<NoexceptMovable>(); }
void assignUsesPrependBuffer_Custom_data() { assignUsesPrependBuffer_data(); }
void assignUsesPrependBuffer_Custom() const { assignUsesPrependBuffer<Custom>(); }
void at() const;
void capacityInt() const { capacity<int>(); }
void capacityMovable() const { capacity<Movable>(); }
+ void capacityNoexceptMovable() const { capacity<NoexceptMovable>(); }
void capacityCustom() const { capacity<Custom>(); }
void clearInt() const { clear<int>(); }
void clearMovable() const { clear<Movable>(); }
+ void clearNoexceptMovable() const { clear<NoexceptMovable>(); }
void clearCustom() const { clear<Custom>(); }
void constData() const;
void constFirst() const;
@@ -263,43 +351,54 @@ private slots:
void contains() const;
void countInt() const { count<int>(); }
void countMovable() const { count<Movable>(); }
+ void countNoexceptMovable() const { count<NoexceptMovable>(); }
void countCustom() const { count<Custom>(); }
void cpp17ctad() const;
void data() const;
void reinterpreted() const;
void emptyInt() const { empty<int>(); }
void emptyMovable() const { empty<Movable>(); }
+ void emptyNoexceptMovable() const { empty<NoexceptMovable>(); }
void emptyCustom() const { empty<Custom>(); }
void endsWith() const;
void eraseEmptyInt() const { eraseEmpty<int>(); }
void eraseEmptyMovable() const { eraseEmpty<Movable>(); }
+ void eraseEmptyNoexceptMovable() const { eraseEmpty<NoexceptMovable>(); }
void eraseEmptyCustom() const { eraseEmpty<Custom>(); }
void eraseEmptyReservedInt() const { eraseEmptyReserved<int>(); }
void eraseEmptyReservedMovable() const { eraseEmptyReserved<Movable>(); }
+ void eraseEmptyReservedNoexceptMovable() const { eraseEmptyReserved<NoexceptMovable>(); }
void eraseEmptyReservedCustom() const { eraseEmptyReserved<Custom>(); }
void eraseInt() const { erase<int>(false); }
void eraseIntShared() const { erase<int>(true); }
void eraseMovable() const { erase<Movable>(false); }
+ void eraseNoexceptMovable() const { erase<NoexceptMovable>(false); }
void eraseMovableShared() const { erase<Movable>(true); }
+ void eraseNoexceptMovableShared() const { erase<NoexceptMovable>(true); }
void eraseCustom() const { erase<Custom>(false); }
void eraseCustomShared() const { erase<Custom>(true); }
void eraseReservedInt() const { eraseReserved<int>(); }
void eraseReservedMovable() const { eraseReserved<Movable>(); }
+ void eraseReservedNoexceptMovable() const { eraseReserved<NoexceptMovable>(); }
void eraseReservedCustom() const { eraseReserved<Custom>(); }
void fillInt() const { fill<int>(); }
void fillMovable() const { fill<Movable>(); }
+ void fillNoexceptMovable() const { fill<NoexceptMovable>(); }
void fillCustom() const { fill<Custom>(); }
void fillDetachInt() const { fillDetach<int>(); }
void fillDetachMovable() const { fillDetach<Movable>(); }
+ void fillDetachNoexceptMovable() const { fillDetach<NoexceptMovable>(); }
void fillDetachCustom() const { fillDetach<Custom>(); }
void first() const;
void freeSpaceAtBeginEventuallyShrinks() const;
void fromListInt() const { fromList<int>(); }
void fromListMovable() const { fromList<Movable>(); }
+ void fromListNoexceptMovable() const { fromList<NoexceptMovable>(); }
void fromListCustom() const { fromList<Custom>(); }
void indexOf() const;
void insertInt() const { insert<int>(); }
void insertMovable() const { insert<Movable>(); }
+ void insertNoexceptMovable() const { insert<NoexceptMovable>(); }
void insertCustom() const { insert<Custom>(); }
void insertZeroCount_data();
void insertZeroCount() const;
@@ -310,17 +409,21 @@ private slots:
void sliced() const;
void moveInt() const { move<int>(); }
void moveMovable() const { move<Movable>(); }
+ void moveNoexceptMovable() const { move<NoexceptMovable>(); }
void moveCustom() const { move<Custom>(); }
void prependInt() const { prepend<int>(); }
void prependMovable() const { prepend<Movable>(); }
+ void prependNoexceptMovable() const { prepend<NoexceptMovable>(); }
void prependCustom() const { prepend<Custom>(); }
void prependRvalue() const;
void qhashInt() const { qhash<int>(); }
void qhashMovable() const { qhash<Movable>(); }
+ void qhashNoexceptMovable() const { qhash<NoexceptMovable>(); }
void qhashCustom() const { qhash<Custom>(); }
void removeAllWithAlias() const;
void removeInt() const { remove<int>(); }
void removeMovable() const { remove<Movable>(); }
+ void removeNoexceptMovable() const { remove<NoexceptMovable>(); }
void removeCustom() const { remove<Custom>(); }
void removeFirstLast() const;
void resizePOD_data() const;
@@ -339,10 +442,12 @@ private slots:
void reverseIterators() const;
void sizeInt() const { size<int>(); }
void sizeMovable() const { size<Movable>(); }
+ void sizeNoexceptMovable() const { size<NoexceptMovable>(); }
void sizeCustom() const { size<Custom>(); }
void startsWith() const;
void swapInt() const { swap<int>(); }
void swapMovable() const { swap<Movable>(); }
+ void swapNoexceptMovable() const { swap<NoexceptMovable>(); }
void swapCustom() const { swap<Custom>(); }
void toAddress() const;
void toList() const;
@@ -356,10 +461,12 @@ private slots:
void reserveZero();
void initializeListInt() { initializeList<int>(); }
void initializeListMovable() { initializeList<Movable>(); }
+ void initializeListNoexceptMovable() { initializeList<NoexceptMovable>(); }
void initializeListCustom() { initializeList<Custom>(); }
void const_shared_null();
void detachInt() const { detach<int>(); }
void detachMovable() const { detach<Movable>(); }
+ void detachNoexceptMovable() const { detach<NoexceptMovable>(); }
void detachCustom() const { detach<Custom>(); }
void detachThreadSafetyInt() const;
void detachThreadSafetyMovable() const;
@@ -369,9 +476,11 @@ private slots:
void emplaceInt() { emplaceImpl<int>(); }
void emplaceCustom() { emplaceImpl<Custom>(); }
void emplaceMovable() { emplaceImpl<Movable>(); }
+ void emplaceNoexceptMovable() { emplaceImpl<NoexceptMovable>(); }
void emplaceConsistentWithStdVectorInt() { emplaceConsistentWithStdVectorImpl<int>(); }
void emplaceConsistentWithStdVectorCustom() { emplaceConsistentWithStdVectorImpl<Custom>(); }
void emplaceConsistentWithStdVectorMovable() { emplaceConsistentWithStdVectorImpl<Movable>(); }
+ void emplaceConsistentWithStdVectorNoexceptMovable() { emplaceConsistentWithStdVectorImpl<NoexceptMovable>(); }
void emplaceConsistentWithStdVectorQString() { emplaceConsistentWithStdVectorImpl<QString>(); }
void emplaceReturnsIterator();
void emplaceFront() const;
@@ -383,35 +492,45 @@ private slots:
void replaceInt() const { replace<int>(); }
void replaceCustom() const { replace<Custom>(); }
void replaceMovable() const { replace<Movable>(); }
+ void replaceNoexceptMovable() const { replace<NoexceptMovable>(); }
void fromReadOnlyData() const;
void reallocateCustomAlignedType_qtbug90359() const;
void reinsertToBeginInt_qtbug91360() const { reinsertToBegin<int>(); }
void reinsertToBeginMovable_qtbug91360() const { reinsertToBegin<Movable>(); }
+ void reinsertToBeginNoexceptMovable_qtbug91360() const { reinsertToBegin<NoexceptMovable>(); }
void reinsertToBeginCustom_qtbug91360() const { reinsertToBegin<Custom>(); }
void reinsertToEndInt_qtbug91360() const { reinsertToEnd<int>(); }
void reinsertToEndMovable_qtbug91360() const { reinsertToEnd<Movable>(); }
+ void reinsertToEndNoexceptMovable_qtbug91360() const { reinsertToEnd<NoexceptMovable>(); }
void reinsertToEndCustom_qtbug91360() const { reinsertToEnd<Custom>(); }
void reinsertRangeToEndInt_qtbug91360() const { reinsertRangeToEnd<int>(); }
void reinsertRangeToEndMovable_qtbug91360() const { reinsertRangeToEnd<Movable>(); }
+ void reinsertRangeToEndNoexceptMovable_qtbug91360() const { reinsertRangeToEnd<NoexceptMovable>(); }
void reinsertRangeToEndCustom_qtbug91360() const { reinsertRangeToEnd<Custom>(); }
// QList reference stability tests:
void stability_reserveInt() const { stability_reserve<int>(); }
void stability_reserveMovable() const { stability_reserve<Movable>(); }
+ void stability_reserveNoexceptMovable() const { stability_reserve<NoexceptMovable>(); }
void stability_reserveCustom() const { stability_reserve<Custom>(); }
void stability_eraseInt() const { stability_erase<int>(); }
void stability_eraseMovable() const { stability_erase<Movable>(); }
+ void stability_eraseNoexceptMovable() const { stability_erase<NoexceptMovable>(); }
void stability_eraseCustom() const { stability_erase<Custom>(); }
void stability_appendInt() const { stability_append<int>(); }
void stability_appendMovable() const { stability_append<Movable>(); }
+ void stability_appendNoexceptMovable() const { stability_append<NoexceptMovable>(); }
void stability_appendCustom() const { stability_append<Custom>(); }
void stability_insertElementInt() const { stability_insertElement<int>(); }
void stability_insertElementMovable() const { stability_insertElement<Movable>(); }
+ void stability_insertElementNoexceptMovable() const { stability_insertElement<NoexceptMovable>(); }
void stability_insertElementCustom() const { stability_insertElement<Custom>(); }
void stability_emplaceInt() const { stability_emplace<int>(); }
void stability_emplaceMovable() const { stability_emplace<Movable>(); }
+ void stability_emplaceNoexceptMovable() const { stability_emplace<NoexceptMovable>(); }
void stability_emplaceCustom() const { stability_emplace<Custom>(); }
void stability_resizeInt() const { stability_resize<int>(); }
void stability_resizeMovable() const { stability_resize<Movable>(); }
+ void stability_resizeNoexceptMovable() const { stability_resize<NoexceptMovable>(); }
void stability_resizeCustom() const { stability_resize<Custom>(); }
private:
@@ -515,16 +634,9 @@ template<typename T> struct SimpleValue
}
static const uint MaxIndex = 6;
- static const T Values[MaxIndex];
+ static inline const T Values[MaxIndex] = { 110, 105, 101, 114, 111, 98 };
};
-template<>
-const int SimpleValue<int>::Values[] = { 110, 105, 101, 114, 111, 98 };
-template<>
-const Movable SimpleValue<Movable>::Values[] = { 110, 105, 101, 114, 111, 98 };
-template<>
-const Custom SimpleValue<Custom>::Values[] = { 110, 105, 101, 114, 111, 98 };
-
// Make some macros for the tests to use in order to be slightly more readable...
#define T_FOO SimpleValue<T>::at(0)
#define T_BAR SimpleValue<T>::at(1)
@@ -656,12 +768,36 @@ void tst_QList::assignFromInitializerList() const
T val2(SimpleValue<T>::at(2));
T val3(SimpleValue<T>::at(3));
- QList<T> v1 = {val1, val2, val3};
+ QList<T> v1 = {};
+ QCOMPARE(v1.size(), 0);
+
+ v1 = {val1, val2, val3};
QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
QCOMPARE(v1, (QList<T> {val1, val2, val3}));
v1 = {};
QCOMPARE(v1.size(), 0);
+
+ // repeat, but make v1 shared before we assign
+ QList v2 = {val3, val1, val2};
+ v1 = v2;
+ v1 = {val1, val2, val3};
+ QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
+ QCOMPARE(v1, (QList<T> {val1, val2, val3}));
+ v1 = v2;
+ v1 = {};
+ QCOMPARE(v1.size(), 0);
+
+ // repeat again, but now detached copies
+ v1 = v2;
+ v1.detach();
+ v1 = {val1, val2, val3};
+ QCOMPARE(v1, QList<T>() << val1 << val2 << val3);
+ QCOMPARE(v1, (QList<T> {val1, val2, val3}));
+ v1 = v2;
+ v1.detach();
+ v1 = {};
+ QCOMPARE(v1.size(), 0);
}
template<typename T>
@@ -834,6 +970,65 @@ void tst_QList::assign() const
QVERIFY(!myvecCopy.isSharedWith(myvec));
QCOMPARE(myvecCopy, QList<T>() << T_FOO << T_FOO);
}
+
+ // test assigning an empty range to an empty list
+ {
+ QList<T> myvec, empty;
+
+ const T *ptr = nullptr;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ ptr = SimpleValue<T>::Values + 3;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+ }
+
+ // test assigning empty to non-empty
+ {
+ QList<T> nonempty = SimpleValue<T>::vector(2);
+ QList<T> myvec;
+
+ const T *ptr = nullptr;
+ myvec = nonempty;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ ptr = SimpleValue<T>::Values + 3;
+ myvec = nonempty;
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ // repeat, after having detached
+ ptr = nullptr;
+ myvec = nonempty;
+ myvec.detach();
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+
+ ptr = SimpleValue<T>::Values + 3;
+ myvec = nonempty;
+ myvec.detach();
+ myvec.assign(ptr, ptr);
+ QVERIFY(myvec.isEmpty());
+ }
+
+ // assign a smaller range
+ {
+ QList<T> myvec = SimpleValue<T>::vector(3);
+ QCOMPARE(myvec.size(), 3);
+
+ myvec.assign(SimpleValue<T>::Values + 3, SimpleValue<T>::Values + 5);
+ QCOMPARE(myvec.size(), 2);
+ QCOMPARE(myvec.at(0), T_CAT);
+ QCOMPARE(myvec.at(1), T_DOG);
+
+ // with detaching:
+ QList copy = myvec;
+ myvec.assign(SimpleValue<T>::Values, SimpleValue<T>::Values + 1);
+ QCOMPARE(myvec.size(), 1);
+ QCOMPARE(myvec.at(0), T_FOO);
+ }
}
inline namespace Scenarios {
@@ -2108,10 +2303,15 @@ void tst_QList::qhash() const
TST_QLIST_CHECK_LEAKS(T)
QList<T> l1, l2;
- QCOMPARE(qHash(l1), qHash(l2));
+ QCOMPARE(qHash(l1, 0), qHash(l2, 0));
l1 << SimpleValue<T>::at(0);
l2 << SimpleValue<T>::at(0);
- QCOMPARE(qHash(l1), qHash(l2));
+ QCOMPARE(qHash(l1, 0), qHash(l2, 0));
+
+ QCOMPARE(qHash(l1, 1), qHash(l2, 1));
+ l1.clear();
+ l2.clear();
+ QCOMPARE(qHash(l1, 1), qHash(l2, 1));
}
template <typename T>
diff --git a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
index 1dadbb9efea..b3f96588304 100644
--- a/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
+++ b/tests/auto/corelib/tools/qscopeguard/tst_qscopeguard.cpp
@@ -26,6 +26,8 @@ private Q_SLOTS:
void optionalGuard();
void leavingScope();
void exceptions();
+
+ void init();
};
void func()
@@ -169,7 +171,6 @@ void tst_QScopeGuard::leavingScope()
void tst_QScopeGuard::exceptions()
{
- s_globalState = 0;
bool caught = false;
QT_TRY
{
@@ -187,5 +188,10 @@ void tst_QScopeGuard::exceptions()
}
+void tst_QScopeGuard::init()
+{
+ s_globalState = 0;
+}
+
QTEST_MAIN(tst_QScopeGuard)
#include "tst_qscopeguard.moc"
diff --git a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
index f7c5af53310..9129fb2e7ed 100644
--- a/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
+++ b/tests/auto/gui/kernel/qwindow/tst_qwindow.cpp
@@ -3244,7 +3244,6 @@ void tst_QWindow::enterLeaveOnWindowShowHide()
QSKIP("We can't move the cursor");
window.show();
- window.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&window));
++expectedEnter;
diff --git a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp
index bd9e00fc376..7b4193e3749 100644
--- a/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp
+++ b/tests/auto/gui/painting/qpainterpath/tst_qpainterpath.cpp
@@ -86,6 +86,9 @@ private slots:
void intersectionPointOnEdge();
void boundsAtStartPoint();
+
+ void percentAtEmptyPath_data();
+ void percentAtEmptyPath();
};
void tst_QPainterPath::cleanupTestCase()
@@ -1637,6 +1640,29 @@ void tst_QPainterPath::boundsAtStartPoint()
QCOMPARE(constructedPath.controlPointRect(), defaultPath.controlPointRect());
}
+void tst_QPainterPath::percentAtEmptyPath_data()
+{
+ const QPointF qpf(2., 2.);
+ QTest::addColumn<QPainterPath>("path");
+
+ QTest::newRow("defaultConstructed") << QPainterPath();
+ QTest::newRow("withStartPoint") << QPainterPath(qpf);
+ QPainterPath pp(qpf);
+ pp.lineTo(qpf);
+ QTest::newRow("equalPoints") << pp;
+}
+
+void tst_QPainterPath::percentAtEmptyPath()
+{
+ QFETCH(QPainterPath, path);
+
+ path.angleAtPercent(0.5);
+ path.pointAtPercent(0.5);
+ path.slopeAtPercent(0.5);
+
+ path.percentAtLength(0);
+}
+
QTEST_APPLESS_MAIN(tst_QPainterPath)
#include "tst_qpainterpath.moc"
diff --git a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
index 0d2b7bfde64..7417f0648e4 100644
--- a/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
+++ b/tests/auto/network/kernel/qhostaddress/tst_qhostaddress.cpp
@@ -30,6 +30,7 @@ public:
tst_QHostAddress();
private slots:
+ void constructor();
void constructor_QString_data();
void constructor_QString();
void setAddress_QString_data();
@@ -62,6 +63,43 @@ tst_QHostAddress::tst_QHostAddress()
qRegisterMetaType<QHostAddress>("QHostAddress");
}
+static void verifyClear(const QHostAddress &addr)
+{
+ QVERIFY(addr.isNull());
+ QVERIFY(!addr.isLoopback());
+ QVERIFY(!addr.isGlobal());
+ QVERIFY(!addr.isLinkLocal());
+ QVERIFY(!addr.isSiteLocal());
+ QVERIFY(!addr.isUniqueLocalUnicast());
+ QVERIFY(!addr.isMulticast());
+ QVERIFY(!addr.isBroadcast());
+ QVERIFY(!addr.isPrivateUse());
+ QCOMPARE(addr, QHostAddress());
+ QCOMPARE(addr, QHostAddress::Null);
+ QCOMPARE(addr.protocol(), QHostAddress::UnknownNetworkLayerProtocol);
+
+ bool ok = true;
+ QCOMPARE(addr.toIPv4Address(&ok), 0);
+ QVERIFY(!ok);
+
+ QCOMPARE(QByteArrayView::fromArray(addr.toIPv6Address().c),
+ QByteArrayView::fromArray(QIPv6Address{}.c));
+ QCOMPARE(addr.scopeId(), QString());
+
+ QCOMPARE(addr.toString(), QString());
+
+ size_t seed = QHashSeed::globalSeed();
+ QCOMPARE(qHash(addr, seed), qHash(QHostAddress(), seed));
+ seed = 0;
+ QCOMPARE(qHash(addr, seed), qHash(QHostAddress(), seed));
+}
+
+void tst_QHostAddress::constructor()
+{
+ QHostAddress addr;
+ verifyClear(addr);
+}
+
void tst_QHostAddress::constructor_QString_data()
{
setAddress_QString_data();
@@ -94,6 +132,9 @@ void tst_QHostAddress::constructor_QString()
QVERIFY( hostAddr.isNull() );
QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
}
+
+ hostAddr.clear();
+ verifyClear(hostAddr);
}
void tst_QHostAddress::setAddress_QString_data()
@@ -201,6 +242,9 @@ void tst_QHostAddress::setAddress_QString()
QVERIFY( hostAddr.isNull() );
QVERIFY( hostAddr.protocol() == QHostAddress::UnknownNetworkLayerProtocol );
}
+
+ hostAddr.clear();
+ verifyClear(hostAddr);
}
void tst_QHostAddress::specialAddresses_data()
@@ -239,6 +283,7 @@ void tst_QHostAddress::specialAddresses()
QFETCH(QHostAddress::SpecialAddress, address);
QFETCH(bool, result);
QCOMPARE(QHostAddress(text) == address, result);
+ size_t seed = QHashSeed::globalSeed();
//check special address equal to itself (QTBUG-22898), note two overloads of operator==
QVERIFY(QHostAddress(address) == QHostAddress(address));
@@ -252,11 +297,19 @@ void tst_QHostAddress::specialAddresses()
QHostAddress ha;
ha.setAddress(address);
QVERIFY(ha == address);
+ QCOMPARE(qHash(ha, seed), qHash(QHostAddress(address), seed));
+ QCOMPARE(qHash(ha, 0), qHash(QHostAddress(address), 0));
}
QHostAddress setter;
setter.setAddress(text);
- QCOMPARE(setter == address, result);
+ if (result) {
+ QCOMPARE(setter, address);
+ QCOMPARE(qHash(setter, seed), qHash(QHostAddress(address), seed));
+ QCOMPARE(qHash(setter, 0), qHash(QHostAddress(address), 0));
+ } else {
+ QCOMPARE_NE(setter, address);
+ }
}
@@ -288,8 +341,11 @@ void tst_QHostAddress::compare()
QCOMPARE(first == second, result);
QCOMPARE(second == first, result);
- if (result == true)
- QCOMPARE(qHash(first), qHash(second));
+ if (result == true) {
+ size_t seed = QHashSeed::globalSeed();
+ QCOMPARE(qHash(first, seed), qHash(second, seed));
+ QCOMPARE(qHash(first, 0), qHash(second, 0));
+ }
}
void tst_QHostAddress::isEqual_data()
@@ -370,6 +426,11 @@ void tst_QHostAddress::scopeId()
address2 = address;
QCOMPARE(address2.scopeId(), QString("eth0"));
QCOMPARE(address2.toString().toLower(), QString("fe80::2e0:4cff:fefb:662a%eth0"));
+
+ address.clear();
+ verifyClear(address);
+ address2.clear();
+ verifyClear(address2);
}
void tst_QHostAddress::hashKey()
diff --git a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
index 4814206cd75..40292f0c44d 100644
--- a/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
+++ b/tests/auto/network/socket/qudpsocket/tst_qudpsocket.cpp
@@ -132,6 +132,7 @@ private:
bool m_skipUnsupportedIPv6Tests;
bool m_workaroundLinuxKernelBug;
+ int loopbackInterface = 0; // unknown by default
QList<QHostAddress> allAddresses;
QHostAddress multicastGroup4, multicastGroup6;
QList<QHostAddress> linklocalMulticastGroups;
@@ -140,6 +141,16 @@ private:
QUdpSocket *m_asyncReceiver;
};
+// Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of obtaining
+// the packet's destination addresses. This means the destinationAddress() be
+// empty, so whitelist the OSes for which we know we have an implementation.
+// That's currently all of them, which means there probably is code in this
+// test that assumes this works without checking this variable.
+//
+// Note: this applies to single-stack operations; dual stack implementations
+// appear to be buggy or not present at all in some OSes.
+static constexpr bool HasWorkingIPv4DestinationAddress = true;
+
#ifdef SHOULD_CHECK_SYSCALL_SUPPORT
bool tst_QUdpSocket::ipv6SetsockoptionMissing(int level, int optname)
{
@@ -246,7 +257,23 @@ void tst_QUdpSocket::initTestCase()
if (!QtNetworkSettings::verifyTestNetworkSettings())
QSKIP("No network test server available");
#endif
- allAddresses = QNetworkInterface::allAddresses();
+
+ allAddresses.clear();
+ for (const QNetworkInterface &iface : QNetworkInterface::allInterfaces()) {
+ if (!iface.flags().testAnyFlags(QNetworkInterface::IsUp))
+ continue;
+ if (iface.flags().testAnyFlags(QNetworkInterface::IsLoopBack))
+ loopbackInterface = iface.index();
+
+ // add this interface's addresses
+ const QList<QNetworkAddressEntry> addresses = iface.addressEntries();
+ for (const QNetworkAddressEntry &entry : addresses) {
+ allAddresses += entry.ip();
+ if (!loopbackInterface && entry.ip().isLoopback())
+ loopbackInterface = iface.index();
+ }
+ }
+
m_skipUnsupportedIPv6Tests = shouldSkipIpv6TestsForBrokenSetsockopt();
// Create a pair of random multicast groups so we avoid clashing with any
@@ -568,12 +595,12 @@ void tst_QUdpSocket::broadcasting()
QVERIFY2(allAddresses.contains(dgram.senderAddress()),
dgram.senderAddress().toString().toLatin1());
QCOMPARE(dgram.senderPort(), int(broadcastSocket.localPort()));
- if (!dgram.destinationAddress().isNull()) {
+ if (HasWorkingIPv4DestinationAddress) {
QVERIFY2(dgram.destinationAddress() == QHostAddress::Broadcast
|| broadcastAddresses.contains(dgram.destinationAddress()),
dgram.destinationAddress().toString().toLatin1());
- QCOMPARE(dgram.destinationPort(), int(serverSocket.localPort()));
}
+ QCOMPARE(dgram.destinationPort(), int(serverSocket.localPort()));
int ttl = dgram.hopLimit();
if (ttl != -1)
@@ -738,15 +765,7 @@ void tst_QUdpSocket::loop()
QCOMPARE(paulDatagram.senderPort(), int(peter.localPort()));
QCOMPARE(peterDatagram.senderPort(), int(paul.localPort()));
- // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
- // obtaining the packet's destination addresses. The destinationAddress and
- // destinationPort calls could fail, so whitelist the OSes for which we
- // know we have an implementation.
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
- QVERIFY(peterDatagram.destinationPort() != -1);
- QVERIFY(paulDatagram.destinationPort() != -1);
-#endif
- if (peterDatagram.destinationPort() == -1) {
+ if (!HasWorkingIPv4DestinationAddress) {
QCOMPARE(peterDatagram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
QCOMPARE(paulDatagram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
} else {
@@ -754,6 +773,11 @@ void tst_QUdpSocket::loop()
QCOMPARE(paulDatagram.destinationAddress(), makeNonAny(paul.localAddress()));
QVERIFY(peterDatagram.destinationAddress().isEqual(makeNonAny(peter.localAddress())));
QVERIFY(paulDatagram.destinationAddress().isEqual(makeNonAny(paul.localAddress())));
+
+ if (loopbackInterface) {
+ QCOMPARE(peterDatagram.interfaceIndex(), loopbackInterface);
+ QCOMPARE(paulDatagram.interfaceIndex(), loopbackInterface);
+ }
}
}
@@ -820,6 +844,11 @@ void tst_QUdpSocket::ipv6Loop()
QCOMPARE(paulDatagram.destinationAddress(), makeNonAny(paul.localAddress()));
QCOMPARE(peterDatagram.destinationPort(), peterPort);
QCOMPARE(paulDatagram.destinationPort(), paulPort);
+
+ if (loopbackInterface) {
+ QCOMPARE(peterDatagram.interfaceIndex(), loopbackInterface);
+ QCOMPARE(paulDatagram.interfaceIndex(), loopbackInterface);
+ }
}
void tst_QUdpSocket::dualStack()
@@ -850,6 +879,8 @@ void tst_QUdpSocket::dualStack()
QCOMPARE(dgram.destinationPort(), int(dualSock.localPort()));
QVERIFY(dgram.destinationAddress().isEqual(makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost)));
} else {
+ // Observed on QNX: the IPV6_PKTINFO ancillary data appears to be
+ // missing if the sender is IPv4.
qInfo("Getting IPv4 destination address failed.");
}
@@ -889,12 +920,11 @@ void tst_QUdpSocket::dualStack()
QCOMPARE(dgram.data(), dualData);
QCOMPARE(dgram.senderPort(), int(dualSock.localPort()));
QCOMPARE(dgram.senderAddress(), makeNonAny(dualSock.localAddress(), QHostAddress::LocalHost));
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
- QVERIFY(dgram.destinationPort() != -1);
-#endif
- if (dgram.destinationPort() != -1) {
- QCOMPARE(dgram.destinationPort(), int(v4Sock.localPort()));
+ QCOMPARE(dgram.destinationPort(), int(v4Sock.localPort()));
+ if (HasWorkingIPv4DestinationAddress) {
QCOMPARE(dgram.destinationAddress(), makeNonAny(v4Sock.localAddress(), QHostAddress::LocalHost));
+ if (loopbackInterface)
+ QCOMPARE(dgram.interfaceIndex(), loopbackInterface);
}
}
@@ -1748,10 +1778,10 @@ void tst_QUdpSocket::multicast()
QVERIFY2(allAddresses.contains(dgram.senderAddress()),
dgram.senderAddress().toString().toLatin1());
QCOMPARE(dgram.senderPort(), int(sender.localPort()));
- if (!dgram.destinationAddress().isNull()) {
+ if (HasWorkingIPv4DestinationAddress) {
QCOMPARE(dgram.destinationAddress(), groupAddress);
- QCOMPARE(dgram.destinationPort(), int(receiver.localPort()));
}
+ QCOMPARE(dgram.destinationPort(), int(receiver.localPort()));
int ttl = dgram.hopLimit();
if (ttl != -1)
@@ -1962,19 +1992,12 @@ void tst_QUdpSocket::linkLocalIPv4()
QCOMPARE(dgram.data().size(), testData.size());
QCOMPARE(dgram.data(), testData);
- // Unlike for IPv6 with IPV6_PKTINFO, IPv4 has no standardized way of
- // obtaining the packet's destination addresses. The destinationAddress
- // and destinationPort calls could fail, so whitelist the OSes we know
- // we have an implementation.
-#if defined(Q_OS_LINUX) || defined(Q_OS_BSD4) || defined(Q_OS_WIN)
- QVERIFY(dgram.destinationPort() != -1);
-#endif
- if (dgram.destinationPort() == -1) {
+ if (!HasWorkingIPv4DestinationAddress) {
QCOMPARE(dgram.destinationAddress().protocol(), QAbstractSocket::UnknownNetworkLayerProtocol);
} else {
QCOMPARE(dgram.destinationAddress(), s->localAddress());
- QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
}
+ QCOMPARE(dgram.destinationPort(), int(neutral.localPort()));
QVERIFY(neutral.writeDatagram(dgram.makeReply(testData)));
QVERIFY2(s->waitForReadyRead(10000), QtNetworkSettings::msgSocketError(*s).constData());
diff --git a/tests/auto/other/qfocusevent/tst_qfocusevent.cpp b/tests/auto/other/qfocusevent/tst_qfocusevent.cpp
index c1b72d4d623..b4cfb0f4f79 100644
--- a/tests/auto/other/qfocusevent/tst_qfocusevent.cpp
+++ b/tests/auto/other/qfocusevent/tst_qfocusevent.cpp
@@ -364,7 +364,6 @@ void tst_QFocusEvent::checkReason_ActiveWindow()
Window window;
window.show();
- window.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&window));
if (windowActivationReasonFail)
@@ -374,7 +373,6 @@ void tst_QFocusEvent::checkReason_ActiveWindow()
Window window2;
window2.show();
- window2.requestActivate();
QVERIFY(QTest::qWaitForWindowActive(&window2));
if (windowActivationReasonFail)
diff --git a/tests/auto/testlib/initmain/tst_initmain.cpp b/tests/auto/testlib/initmain/tst_initmain.cpp
index 75a0d9ceb4d..cdaac0c14f4 100644
--- a/tests/auto/testlib/initmain/tst_initmain.cpp
+++ b/tests/auto/testlib/initmain/tst_initmain.cpp
@@ -19,6 +19,9 @@ private:
static bool m_initMainCalled;
};
+static_assert(QTest::Internals::HasInitMain<tst_InitMain>::value);
+static_assert(!QTest::Internals::HasInitMain<QObject>::value);
+
bool tst_InitMain::m_initMainCalled = false;
void tst_InitMain::testcase()
diff --git a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
index 17acdea014e..2f0cbf78b25 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsproxywidget/tst_qgraphicsproxywidget.cpp
@@ -25,6 +25,7 @@
#include <QtWidgets/qtablewidget.h>
#include <QtGui/qevent.h>
+#include <QtGui/qstylehints.h>
#include <QtGui/private/qhighdpiscaling_p.h>
#include <QtCore/qmimedata.h>
@@ -3333,7 +3334,7 @@ void tst_QGraphicsProxyWidget::clickFocus()
EventSpy proxySpy(proxy);
EventSpy widgetSpy(proxy->widget());
- view.setFrameStyle(0);
+ view.setFrameStyle(QFrame::NoFrame);
view.resize(300, 300);
view.show();
QVERIFY(QTest::qWaitForWindowFocused(&view));
@@ -3469,10 +3470,12 @@ void tst_QGraphicsProxyWidget::QTBUG_6986_sendMouseEventToAlienWidget()
auto *hoverButton = new HoverButton(background);
hoverButton->setText("Second button"_L1);
hoverButton->setGeometry(10, 10, 200, 50);
+ hoverButton->setAttribute(Qt::WA_Hover, true);
scene.addWidget(background);
auto *hideButton = new QPushButton("I'm a button with a very very long text"_L1);
hideButton->setGeometry(10, 10, 400, 50);
+ hideButton->setAttribute(Qt::WA_Hover, true);
QGraphicsProxyWidget *topButton = scene.addWidget(hideButton);
connect(hideButton, &QPushButton::clicked, &scene, [&]() { topButton->hide(); });
topButton->setFocus();
@@ -3659,6 +3662,11 @@ public:
return QWidget::event(event);
}
+ void paintEvent(QPaintEvent *) override
+ {
+ QPainter p(this);
+ p.fillRect(rect(), Qt::green);
+ }
};
#if QT_CONFIG(wheelevent)
@@ -3676,6 +3684,11 @@ public:
*/
void tst_QGraphicsProxyWidget::wheelEventPropagation()
{
+ qApp->styleHints()->setWheelScrollLines(3);
+ const auto guard = qScopeGuard([&]() {
+ qApp->styleHints()->setWheelScrollLines(-1);
+ });
+
QGraphicsScene scene(0, 0, 600, 600);
auto *label = new QLabel("Direct"_L1);
@@ -3697,6 +3710,11 @@ void tst_QGraphicsProxyWidget::wheelEventPropagation()
int wheelEventCount = 0;
protected:
+ void paintEvent(QPaintEvent *) override
+ {
+ QPainter p(this);
+ p.fillRect(rect(), Qt::green);
+ }
void wheelEvent(QWheelEvent *) override
{
++wheelEventCount;
@@ -3710,10 +3728,13 @@ void tst_QGraphicsProxyWidget::wheelEventPropagation()
QGraphicsView view(&scene);
view.setFixedHeight(200);
+ view.setFixedWidth(700);
+ view.setFrameStyle(QFrame::NoFrame);
view.show();
QVERIFY(QTest::qWaitForWindowActive(&view));
QVERIFY(view.verticalScrollBar()->isVisible());
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
view.verticalScrollBar()->setValue(0);
QSignalSpy scrollSpy(view.verticalScrollBar(), &QScrollBar::valueChanged);
@@ -3729,6 +3750,8 @@ void tst_QGraphicsProxyWidget::wheelEventPropagation()
phase);
QCoreApplication::processEvents();
};
+ auto vs = view.verticalScrollBar();
+ vs->setSingleStep(9); // each wheel event: wheelScrollLines() * 9 = 27px
qsizetype scrollCount = 0;
// test non-kinetic events; they are not grabbed, and should scroll the view unless
@@ -3816,6 +3839,7 @@ void tst_QGraphicsProxyWidget::forwardTouchEvent()
QGraphicsView view(&scene);
view.show();
+ view.setFrameStyle(QFrame::NoFrame);
QVERIFY(QTest::qWaitForWindowActive(&view));
EventSpy eventSpy(widget);
@@ -3832,16 +3856,14 @@ void tst_QGraphicsProxyWidget::forwardTouchEvent()
QTest::touchEvent(&view, device.get()).move(0, QPoint(16, 16), &view);
QTest::touchEvent(&view, device.get()).release(0, QPoint(15, 15), &view);
- QApplication::processEvents();
-
- QCOMPARE(eventSpy.counts[QEvent::TouchBegin], 1);
- QCOMPARE(eventSpy.counts[QEvent::TouchUpdate], 2);
- QCOMPARE(eventSpy.counts[QEvent::TouchEnd], 1);
+ QTRY_COMPARE(eventSpy.counts[QEvent::TouchBegin], 1);
+ QTRY_COMPARE(eventSpy.counts[QEvent::TouchUpdate], 2);
+ QTRY_COMPARE(eventSpy.counts[QEvent::TouchEnd], 1);
}
void tst_QGraphicsProxyWidget::touchEventPropagation()
{
- QGraphicsScene scene(0, 0, 300, 200);
+ QGraphicsScene scene;
auto *simpleWidget = new QWidget;
simpleWidget->setObjectName("simpleWidget");
simpleWidget->setAttribute(Qt::WA_AcceptTouchEvents, true);
@@ -3873,15 +3895,26 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
vbox->addWidget(touchWidget2);
QGraphicsProxyWidget *formProxy = scene.addWidget(formWidget);
formProxy->setAcceptTouchEvents(true);
- formProxy->setGeometry(QRectF(50, 50, 200, 160));
+ const auto minSize = formWidget->minimumSize();
+ formProxy->setGeometry(QRectF(50, 50, minSize.width(), minSize.height()));
+
+ // topLeft must be 0/0
+ const auto sceneRect = scene.sceneRect();
+ scene.setSceneRect(QRectF(0, 0, sceneRect.width(), sceneRect.height()));
QGraphicsView view(&scene);
+ // by setting NoFrame, view and view.viewport() have the same
+ // coordinate system
+ view.setFrameStyle(QFrame::NoFrame);
+ // make sure to not have scrollbars
view.setFixedSize(scene.width(), scene.height());
view.verticalScrollBar()->setValue(0);
view.horizontalScrollBar()->setValue(0);
view.viewport()->setObjectName("GraphicsView's Viewport");
view.show();
QVERIFY(QTest::qWaitForWindowExposed(&view));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
class TouchEventSpy : public QObject
{
@@ -3913,8 +3946,12 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
case QEvent::TouchEnd: {
auto *touchEvent = static_cast<QTouchEvent *>(event);
// instead of detaching each QEventPoint, just store the relative positions
- for (const auto &touchPoint : touchEvent->points())
- records[touchPoint.id()] << TouchRecord{receiver, event->type(), touchPoint.position()};
+ for (const auto& touchPoint : touchEvent->points()) {
+ records[touchPoint.id()]
+ << TouchRecord{ receiver, event->type(), touchPoint.position() };
+ qCDebug(lcTests) << touchPoint.id() << "recv:" << receiver << "type"
+ << event->type() << "pos" << touchPoint.position();
+ }
qCDebug(lcTests) << "Recording" << event << receiver;
break;
}
@@ -3944,9 +3981,9 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
};
// verify that the embedded widget gets the correctly translated event
- QTest::touchEvent(&view, touchDevice.get()).press(0, simpleCenter.toPoint());
+ QTest::touchEvent(&view, touchDevice.get()).press(0, view.mapFromScene(simpleCenter));
// window, viewport, scene, simpleProxy, simpleWidget
- QCOMPARE(eventSpy.count(), 5);
+ QTRY_COMPARE(eventSpy.count(), 5);
QCOMPARE(eventSpy.at(0).receiver, view.windowHandle());
QCOMPARE(eventSpy.at(1).receiver, view.viewport());
QCOMPARE(eventSpy.at(2).receiver, &scene);
@@ -3969,7 +4006,7 @@ void tst_QGraphicsProxyWidget::touchEventPropagation()
QCOMPARE(formWidget->childAt(touchWidget2->pos() + tw2Center), touchWidget2);
// touch events are sent to the view, in view coordinates
- const QPoint formProxyPox = view.mapFromScene(formProxy->pos().toPoint());
+ const QPoint formProxyPox = view.mapFromScene(formProxy->pos());
const QPoint pb1TouchPos = pushButton1->pos() + pb1Center + formProxyPox;
const QPoint pb2TouchPos = pushButton2->pos() + pb2Center + formProxyPox;
const QPoint tw1TouchPos = touchWidget1->pos() + tw1Center + formProxyPox;
diff --git a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
index df19ea1568e..878c5a8f39a 100644
--- a/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
+++ b/tests/auto/widgets/graphicsview/qgraphicsview/tst_qgraphicsview.cpp
@@ -1625,19 +1625,19 @@ void tst_QGraphicsView::itemsInRect_cosmeticAdjust_data()
QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 0 << false;
// Anti-aliased.
- QTest::newRow("nil") << QRect() << 1 << true;
- QTest::newRow("0, 0, 300, 100") << QRect(0, 0, 300, 100) << 1 << true;
- QTest::newRow("0, 0, 100, 300") << QRect(0, 0, 100, 300) << 1 << true;
- QTest::newRow("200, 0, 100, 300") << QRect(200, 0, 100, 300) << 1 << true;
- QTest::newRow("0, 200, 300, 100") << QRect(0, 200, 300, 100) << 1 << true;
- QTest::newRow("0, 0, 300, 99") << QRect(0, 0, 300, 99) << 1 << true;
- QTest::newRow("0, 0, 99, 300") << QRect(0, 0, 99, 300) << 1 << true;
- QTest::newRow("201, 0, 99, 300") << QRect(201, 0, 99, 300) << 1 << true;
- QTest::newRow("0, 201, 300, 99") << QRect(0, 201, 300, 99) << 1 << true;
- QTest::newRow("0, 0, 300, 98") << QRect(0, 0, 300, 98) << 0 << false;
- QTest::newRow("0, 0, 98, 300") << QRect(0, 0, 98, 300) << 0 << false;
- QTest::newRow("202, 0, 98, 300") << QRect(202, 0, 98, 300) << 0 << false;
- QTest::newRow("0, 202, 300, 98") << QRect(0, 202, 300, 98) << 0 << false;
+ QTest::newRow("nil, antiAliased") << QRect() << 1 << true;
+ QTest::newRow("0, 0, 300, 100, antiAliased") << QRect(0, 0, 300, 100) << 1 << true;
+ QTest::newRow("0, 0, 100, 300, antiAliased") << QRect(0, 0, 100, 300) << 1 << true;
+ QTest::newRow("200, 0, 100, 300, antiAliased") << QRect(200, 0, 100, 300) << 1 << true;
+ QTest::newRow("0, 200, 300, 100, antiAliased") << QRect(0, 200, 300, 100) << 1 << true;
+ QTest::newRow("0, 0, 300, 99, antiAliased") << QRect(0, 0, 300, 99) << 1 << true;
+ QTest::newRow("0, 0, 99, 300, antiAliased") << QRect(0, 0, 99, 300) << 1 << true;
+ QTest::newRow("201, 0, 99, 300, antiAliased") << QRect(201, 0, 99, 300) << 1 << true;
+ QTest::newRow("0, 201, 300, 99, antiAliased") << QRect(0, 201, 300, 99) << 1 << true;
+ QTest::newRow("0, 0, 300, 98, antiAliased") << QRect(0, 0, 300, 98) << 0 << false;
+ QTest::newRow("0, 0, 98, 300, antiAliased") << QRect(0, 0, 98, 300) << 0 << false;
+ QTest::newRow("202, 0, 98, 300, antiAliased") << QRect(202, 0, 98, 300) << 0 << false;
+ QTest::newRow("0, 202, 300, 98, antiAliased") << QRect(0, 202, 300, 98) << 0 << false;
}
void tst_QGraphicsView::itemsInRect_cosmeticAdjust()
@@ -1833,11 +1833,7 @@ void tst_QGraphicsView::itemAt2()
void tst_QGraphicsView::mapToScene()
{
- // Uncomment the commented-out code to see what's going on. It doesn't
- // affect the test; it just slows it down.
-
QGraphicsScene scene;
- scene.addPixmap(QPixmap("3D-Qt-1-2.png"));
QWidget topLevel;
QGraphicsView view(&topLevel);
@@ -1847,16 +1843,11 @@ void tst_QGraphicsView::mapToScene()
view.setFixedSize(viewSize);
topLevel.show();
- QApplication::processEvents();
- QVERIFY(view.isVisible());
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QCOMPARE(view.size(), viewSize);
// First once without setting the scene rect
-#ifdef Q_PROCESSOR_ARM
- const int step = 20;
-#else
const int step = 5;
-#endif
for (int x = 0; x < view.width(); x += step) {
for (int y = 0; y < view.height(); y += step) {
@@ -1920,20 +1911,21 @@ void tst_QGraphicsView::mapToSceneRect_data()
QTest::addColumn<QPolygonF>("scenePoly");
QTest::addColumn<qreal>("rotation");
- QTest::newRow("nil") << QRect() << QPolygonF() << qreal(0);
- QTest::newRow("0, 0, 1, 1") << QRect(0, 0, 1, 1) << QPolygonF(QRectF(0, 0, 1, 1)) << qreal(0);
- QTest::newRow("0, 0, 10, 10") << QRect(0, 0, 10, 10) << QPolygonF(QRectF(0, 0, 10, 10)) << qreal(0);
- QTest::newRow("nil") << QRect() << QPolygonF() << qreal(90);
- QPolygonF p;
- p << QPointF(0, 0) << QPointF(0, -1) << QPointF(1, -1) << QPointF(1, 0) << QPointF(0, 0);
- QTest::newRow("0, 0, 1, 1") << QRect(0, 0, 1, 1)
- << p
- << qreal(90);
- p.clear();
- p << QPointF(0, 0) << QPointF(0, -10) << QPointF(10, -10) << QPointF(10, 0) << QPointF(0, 0);
- QTest::newRow("0, 0, 10, 10") << QRect(0, 0, 10, 10)
- << p
- << qreal(90);
+ const auto translate90 = [&](const QPolygonF &poly) -> QPolygonF {
+ const QTransform mat = QTransform().rotate(-90); // the view is rotated
+ return mat.map(QPolygonF(poly));
+ };
+
+ constexpr QRect r1(0, 0, 1, 1);
+ constexpr QRect r2(0, 0, 10, 10);
+ const QPolygonF p1 = QPolygonF(QRectF(r1));
+ const QPolygonF p2 = QPolygonF(QRectF(r2));
+ QTest::newRow("nil, no rotation") << QRect() << QPolygonF() << qreal(0);
+ QTest::newRow("0, 0, 1, 1, no rotation") << r1 << p1 << qreal(0);
+ QTest::newRow("0, 0, 10, 10, no rotation") << r2 << p2 << qreal(0);
+ QTest::newRow("nil, 90 degree") << QRect() << QPolygonF() << qreal(90);
+ QTest::newRow("0, 0, 1, 1, 90 degree") << r1 << translate90(p1) << qreal(90);
+ QTest::newRow("0, 0, 10, 10, 90 degree") << r2 << translate90(p2) << qreal(90);
}
void tst_QGraphicsView::mapToSceneRect()
@@ -1954,6 +1946,7 @@ void tst_QGraphicsView::mapToSceneRect()
view.setTransformationAnchor(QGraphicsView::NoAnchor);
view.setResizeAnchor(QGraphicsView::NoAnchor);
view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
view.rotate(rotation);
@@ -1972,20 +1965,16 @@ void tst_QGraphicsView::mapToScenePoly()
view.translate(100, 100);
view.setFixedSize(117, 117);
view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QPoint center = view.viewport()->rect().center();
QRect rect(center + QPoint(10, 0), QSize(10, 10));
- QPolygon poly;
- poly << rect.topLeft();
- poly << rect.topRight();
- poly << rect.bottomRight();
- poly << rect.bottomLeft();
-
- QPolygonF poly2;
- poly2 << view.mapToScene(rect.topLeft());
- poly2 << view.mapToScene(rect.topRight());
- poly2 << view.mapToScene(rect.bottomRight());
- poly2 << view.mapToScene(rect.bottomLeft());
+ const QPolygon poly = { rect.topLeft(), rect.topRight(),
+ rect.bottomRight(), rect.bottomLeft() };
+ const QPolygonF poly2 = { view.mapToScene(rect.topLeft()),
+ view.mapToScene(rect.topRight()),
+ view.mapToScene(rect.bottomRight()),
+ view.mapToScene(rect.bottomLeft()) };
QCOMPARE(view.mapToScene(poly), poly2);
}
@@ -1998,6 +1987,7 @@ void tst_QGraphicsView::mapToScenePath()
view.translate(10, 10);
view.setFixedSize(300, 300);
view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QRect rect(QPoint(10, 0), QSize(10, 10));
QPainterPath path;
@@ -2019,6 +2009,7 @@ void tst_QGraphicsView::mapFromScenePoint()
view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
QPoint mapped = view.mapFromScene(0, 0);
QPoint center = view.viewport()->rect().center();
@@ -2038,6 +2029,7 @@ void tst_QGraphicsView::mapFromScenePoint()
view.ensurePolished();
view.resize(view.sizeHint());
toplevel.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&toplevel));
QCOMPARE(view.mapFromScene(0, 0), QPoint(0, 0));
QCOMPARE(view.mapFromScene(0.4, 0.4), QPoint(0, 0));
@@ -2058,28 +2050,21 @@ void tst_QGraphicsView::mapFromSceneRect()
QWidget topLevel;
QGraphicsView view(&scene,&topLevel);
view.rotate(90);
- view.setFixedSize(200, 200);
- view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ const auto fw = view.frameWidth() * 2;
+ view.setFixedSize(200 + fw, 200 + fw);
topLevel.show();
- QVERIFY(QTest::qWaitForWindowActive(&view));
-
- QPolygon polygon;
- polygon << QPoint(98, 98);
- polygon << QPoint(98, 108);
- polygon << QPoint(88, 108);
- polygon << QPoint(88, 98);
+ QVERIFY(QTest::qWaitForWindowActive(&topLevel));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
-
- QPolygon viewPolygon = view.mapFromScene(0, 0, 10, 10);
- for (int i = 0; i < 4; ++i) {
- QVERIFY(qAbs(viewPolygon[i].x() - polygon[i].x()) < 3);
- QVERIFY(qAbs(viewPolygon[i].y() - polygon[i].y()) < 3);
- }
+ const QRectF input(0, 0, 10, 10);
+ // fixed size is 200x200 so center is 100x100
+ const QPolygon polygon{ QPoint(100, 100), QPoint(100, 110), QPoint(90, 110), QPoint(90, 100) };
+ const QPolygon viewPolygon = view.mapFromScene(input);
+ QCOMPARE(viewPolygon, polygon);
QPoint pt = view.mapFromScene(QPointF());
- QPolygon p;
- p << pt << pt << pt << pt;
+ QPolygon p{ pt, pt, pt, pt };
QCOMPARE(view.mapFromScene(QRectF()), p);
}
@@ -2088,28 +2073,18 @@ void tst_QGraphicsView::mapFromScenePoly()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.rotate(90);
- view.setFixedSize(200, 200);
- view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ const auto fw = view.frameWidth() * 2;
+ view.setFixedSize(200 + fw, 200 + fw);
view.show();
-
- QPolygonF polygon;
- polygon << QPoint(0, 0);
- polygon << QPoint(10, 0);
- polygon << QPoint(10, 10);
- polygon << QPoint(0, 10);
-
- QPolygon polygon2;
- polygon2 << QPoint(98, 98);
- polygon2 << QPoint(98, 108);
- polygon2 << QPoint(88, 108);
- polygon2 << QPoint(88, 98);
-
- QPolygon viewPolygon = view.mapFromScene(polygon);
- for (int i = 0; i < 4; ++i) {
- QVERIFY(qAbs(viewPolygon[i].x() - polygon2[i].x()) < 3);
- QVERIFY(qAbs(viewPolygon[i].y() - polygon2[i].y()) < 3);
- }
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
+
+ const QPolygonF input{ QPoint(0, 0), QPoint(10, 0), QPoint(10, 10), QPoint(0, 10) };
+ // fixed size is 200x200 so center is 100x100
+ const QPolygon polygon{ QPoint(100, 100), QPoint(100, 110), QPoint(90, 110), QPoint(90, 100) };
+ const QPolygon viewPolygon = view.mapFromScene(input);
+ QCOMPARE(viewPolygon, polygon);
}
void tst_QGraphicsView::mapFromScenePath()
@@ -2117,34 +2092,22 @@ void tst_QGraphicsView::mapFromScenePath()
QGraphicsScene scene;
QGraphicsView view(&scene);
view.rotate(90);
- view.setFixedSize(200, 200);
- view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ const auto fw = view.frameWidth() * 2;
+ view.setFixedSize(200 + fw, 200 + fw);
view.show();
-
- QPolygonF polygon;
- polygon << QPoint(0, 0);
- polygon << QPoint(10, 0);
- polygon << QPoint(10, 10);
- polygon << QPoint(0, 10);
+ QVERIFY(QTest::qWaitForWindowActive(&view));
+ QVERIFY(!view.horizontalScrollBar()->isVisible());
+ QVERIFY(!view.verticalScrollBar()->isVisible());
+
+ const QPolygonF input{ QPoint(0, 0), QPoint(10, 0), QPoint(10, 10), QPoint(0, 10) };
+ QPainterPath inputPath;
+ inputPath.addPolygon(input);
+ // fixed size is 200x200 so center is 100x100
+ const QPolygon polygon{ QPoint(100, 100), QPoint(100, 110), QPoint(90, 110), QPoint(90, 100) };
QPainterPath path;
path.addPolygon(polygon);
-
- QPolygon polygon2;
- polygon2 << QPoint(98, 98);
- polygon2 << QPoint(98, 108);
- polygon2 << QPoint(88, 108);
- polygon2 << QPoint(88, 98);
- QPainterPath path2;
- path2.addPolygon(polygon2);
-
- QPolygonF pathPoly = view.mapFromScene(path).toFillPolygon();
- QPolygonF path2Poly = path2.toFillPolygon();
-
- for (int i = 0; i < pathPoly.size(); ++i) {
- QVERIFY(qAbs(pathPoly[i].x() - path2Poly[i].x()) < 3);
- QVERIFY(qAbs(pathPoly[i].y() - path2Poly[i].y()) < 3);
- }
+ QPainterPath viewPath = view.mapFromScene(inputPath);
+ QCOMPARE(viewPath, path);
}
void tst_QGraphicsView::sendEvent()
@@ -2828,15 +2791,15 @@ void tst_QGraphicsView::levelOfDetail_data()
QTest::newRow("1:4, 1:4") << QTransform().scale(0.25, 0.25) << qreal(0.25);
QTest::newRow("1:2, 1:4") << QTransform().scale(0.5, 0.25) << qreal(::sqrt(0.125));
- QTest::newRow("4:1, 1:2") << QTransform().scale(0.25, 0.5) << qreal(::sqrt(0.125));
+ QTest::newRow("1:4, 1:2") << QTransform().scale(0.25, 0.5) << qreal(::sqrt(0.125));
QTest::newRow("1:2, 1:2") << QTransform().scale(0.5, 0.5) << qreal(0.5);
QTest::newRow("1:1, 1:2") << QTransform().scale(1, 0.5) << qreal(::sqrt(0.5));
- QTest::newRow("2:1, 1:1") << QTransform().scale(0.5, 1) << qreal(::sqrt(0.5));
+ QTest::newRow("1:2, 1:1") << QTransform().scale(0.5, 1) << qreal(::sqrt(0.5));
QTest::newRow("1:1, 1:1") << QTransform().scale(1, 1) << qreal(1.0);
QTest::newRow("2:1, 1:1") << QTransform().scale(2, 1) << qreal(::sqrt(2.0));
- QTest::newRow("1:1, 2:1") << QTransform().scale(2, 1) << qreal(::sqrt(2.0));
+ QTest::newRow("1:1, 2:1") << QTransform().scale(1, 2) << qreal(::sqrt(2.0));
QTest::newRow("2:1, 2:1") << QTransform().scale(2, 2) << qreal(2.0);
QTest::newRow("2:1, 4:1") << QTransform().scale(2, 4) << qreal(::sqrt(8.0));
QTest::newRow("4:1, 2:1") << QTransform().scale(4, 2) << qreal(::sqrt(8.0));
diff --git a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
index 8e46876934d..e3d172c60c0 100644
--- a/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
+++ b/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp
@@ -187,6 +187,7 @@ private slots:
void mapFromAndTo();
void focusChainOnHide();
void focusChainOnReparent();
+ void focusChainOnReparentNoChange();
void focusAbstraction();
void defaultTabOrder();
void reverseTabOrder();
@@ -1983,6 +1984,82 @@ void tst_QWidget::focusChainOnReparent()
}
}
+//#define DEBUG_FOCUS_CHAIN
+static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nullptr)
+{
+#ifdef DEBUG_FOCUS_CHAIN
+ qDebug() << "Dump focus chain, start:" << start << "isForward:" << bForward << desc;
+ QWidget *cur = start;
+ do {
+ qDebug() << "-" << cur << cur->objectName();
+ auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
+ cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
+ } while (cur != start);
+#else
+ Q_UNUSED(start);
+ Q_UNUSED(bForward);
+ Q_UNUSED(desc);
+#endif
+}
+
+void tst_QWidget::focusChainOnReparentNoChange()
+{
+ QWidget window;
+
+ auto new_QWidget = [](QWidget *parent, const char *name) {
+ QWidget *w = new QWidget(parent);
+ w->setObjectName(name);
+ return w;
+ };
+ QWidget *child1 = new_QWidget(&window, "child1");
+ QWidget *child2 = new_QWidget(&window, "child2");
+ QWidget *child3 = new_QWidget(&window, "child3");
+ QWidget *child21 = new_QWidget(child2, "child21");
+ QWidget *child22 = new_QWidget(child2, "child22");
+ QWidget *child4 = new_QWidget(&window, "child4");
+
+ dumpFocusChain(&window, true);
+
+ QWidget *expectedOriginalChain[8] = {&window, child1, child2, child3, child21, child22, child4, &window};
+ QWidget *w = &window;
+ for (auto expectedOriginal : expectedOriginalChain) {
+ QCOMPARE(w, expectedOriginal);
+ w = w->nextInFocusChain();
+ }
+ for (int i = 7; i >= 0; --i) {
+ w = w->previousInFocusChain();
+ QCOMPARE(w, expectedOriginalChain[i]);
+ }
+
+ child2->setParent(child4);
+ child22->setParent(&window);
+ dumpFocusChain(&window, true);
+
+ /*
+ * child2 and child22 was reparented *within* the &window hierarchy
+ * Hierarchy is now:
+ *
+ * - window
+ * - child1
+ * - child3
+ * - child4
+ * - child2
+ * - child21
+ * - child22
+ *
+ * but focus chain remains the same (it depends on the order of widget construction)
+ */
+ QWidget *expectedNewChain[8] = {&window, child1, child2, child3, child21, child22, child4, &window};
+ w = &window;
+ for (auto expectedNew : expectedNewChain) {
+ QCOMPARE(w, expectedNew);
+ w = w->nextInFocusChain();
+ }
+ for (int i = 7; i >= 0; --i) {
+ w = w->previousInFocusChain();
+ QCOMPARE(w, expectedNewChain[i]);
+ }
+}
void tst_QWidget::focusChainOnHide()
{
@@ -2536,24 +2613,6 @@ void tst_QWidget::tabOrderWithProxyDisabled()
qPrintable(focusWidgetName()));
}
-//#define DEBUG_FOCUS_CHAIN
-static void dumpFocusChain(QWidget *start, bool bForward, const char *desc = nullptr)
-{
-#ifdef DEBUG_FOCUS_CHAIN
- qDebug() << "Dump focus chain, start:" << start << "isForward:" << bForward << desc;
- QWidget *cur = start;
- do {
- qDebug() << "-" << cur;
- auto widgetPrivate = static_cast<QWidgetPrivate *>(qt_widget_private(cur));
- cur = bForward ? widgetPrivate->focus_next : widgetPrivate->focus_prev;
- } while (cur != start);
-#else
- Q_UNUSED(start);
- Q_UNUSED(bForward);
- Q_UNUSED(desc);
-#endif
-}
-
void tst_QWidget::tabOrderWithCompoundWidgets()
{
if (QGuiApplication::platformName().startsWith(QLatin1String("wayland"), Qt::CaseInsensitive))
diff --git a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
index 8ee122ece18..6859f22c044 100644
--- a/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
+++ b/tests/auto/widgets/widgets/qcombobox/tst_qcombobox.cpp
@@ -842,6 +842,20 @@ void tst_QComboBox::virtualAutocompletion()
QApplication::sendEvent(testWidget, &kp2);
QApplication::sendEvent(testWidget, &kr2);
QTRY_COMPARE(testWidget->currentIndex(), 3);
+
+ QKeyEvent kp3(QEvent::KeyPress, Qt::Key_R, {}, "r");
+ QKeyEvent kr3(QEvent::KeyRelease, Qt::Key_R, {}, "r");
+ QTest::qWait(QApplication::keyboardInputInterval());
+ QApplication::sendEvent(testWidget, &kp3);
+ QApplication::sendEvent(testWidget, &kr3);
+ QTRY_COMPARE(testWidget->currentIndex(), 3);
+
+ QTest::qWait(QApplication::keyboardInputInterval());
+ testWidget->view()->setKeyboardSearchFlags(Qt::MatchContains | Qt::MatchWrap);
+ QApplication::sendEvent(testWidget, &kp3);
+ QApplication::sendEvent(testWidget, &kr3);
+ QTRY_COMPARE(testWidget->currentIndex(), 1);
+
#if defined(Q_PROCESSOR_ARM) || defined(Q_PROCESSOR_MIPS)
QApplication::setKeyboardInputInterval(oldInterval);
#endif
diff --git a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
index 4de87cdb7a4..704770edfcc 100644
--- a/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
+++ b/tests/auto/widgets/widgets/qmenubar/tst_qmenubar.cpp
@@ -19,8 +19,9 @@
#include <QTranslator>
#include <qscreen.h>
-#include <qobject.h>
+#include <QtCore/qobject.h>
#include <QtCore/qscopeguard.h>
+#include <QtCore/qtimer.h>
#include <QtWidgets/private/qapplication_p.h>
@@ -129,6 +130,8 @@ private slots:
void pressDragRelease_data();
void pressDragRelease();
+ void setActiveAction_disablesSloppyTimer();
+
protected slots:
void onSimpleActivated( QAction*);
void onComplexActionTriggered();
@@ -1525,6 +1528,50 @@ void tst_QMenuBar::pressDragRelease()
QTRY_COMPARE(triggeredSpy.size(), 1);
}
+void tst_QMenuBar::setActiveAction_disablesSloppyTimer()
+{
+ QMenuBar menuBar;
+ QMenu *menu = new QMenu(&menuBar);
+ menuBar.addMenu(menu);
+
+ QAction *item1 = menu->addAction("Item 1");
+ QAction *item2 = menu->addAction("Item 2");
+
+ // Create submenu for first item
+ QMenu *submenu = new QMenu(&menuBar);
+ submenu->addAction("Subitem 1");
+ submenu->addAction("Subitem 2");
+ submenu->addAction("Subitem 3");
+ item1->setMenu(submenu);
+
+ using namespace std::chrono_literals;
+
+ QTimer::singleShot(0, [&]() {
+ menu->show();
+ });
+
+ QTimer::singleShot(100ms, [&]() {
+ menu->setActiveAction(item1);
+ QCOMPARE_EQ(menu->activeAction(), item1);
+ });
+
+ QTimer::singleShot(200ms, [&] {
+ menu->setActiveAction(item2);
+ QCOMPARE_EQ(menu->activeAction(), item2);
+ });
+
+ bool done = false;
+ // QTBUG-138956: sloppy timer should not fire when calling setActiveAction
+ QTimer::singleShot(2s, [&] {
+ QCOMPARE_EQ(menu->activeAction(), item2);
+ done = true;
+ });
+
+ QVERIFY(QTest::qWaitFor([&]{
+ return done;
+ }));
+}
+
// QTBUG-56526
void tst_QMenuBar::platformMenu()
{