diff options
Diffstat (limited to 'tests')
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() { |
